问题
Problem statement:
Given the interactive input, call the appropriate methods on appropriate objects (Bank, BankRegister, BasicAccount, etc...).
input (each command on a separate line):
create_bank <bank_name>\n
create_customer <bank_number> <customer_name>\n
create_account <bank_number> <customer_number>\n
deposit <amount> <account_number>/<bank_number>\n
etc...
Proposed solution:
#include <functional>
bool create_bank(const string& arguments){
const string& bankName = arguments; //no need to parse here
bankRegister.registerBank(new Bank(bankName,
&bankRegister)); //can't access bankRegister!
return true;
}
int main(){
map<string, function<bool (string)>> commands;
commands.emplace("create_bank",create_bank);
...
BankRegister bankRegister;
string command, arguments;
cin>>command;
getline(cin, arguments);
commands[command](arguments);
...
}
Why it does not work:
- The bankRegister object can't be accessed from the functions. I might pass it by constant reference to the functions, but only some functions need it. I was thinking of making its members (m_banks, m_next_bankNumber) static, but then I would have to make them public, which is probably a bad design decision.
- Where should the argument parsing happen? Is it OK this way?
What should the return value represent?
a) arguments parsed successfully
b) arguments parsed successfully and command executed successfully
I use the exceptions for some of the errors, but some are silent except for cerr.
Could I use variadic functions here to parse the arguments?
- Is there something else you would improve?
回答1:
You could change the signature of the create_bank
function and use std::bind
to bind the BankRegister
argument, creating a function object with the call signature bool(const string&)
bool create_bank(const string& arguments, BankRegister& bankRegister){
const string& bankName = arguments; //no need to parse here
bankRegister.registerBank(new Bank(bankName,
&bankRegister));
return true;
}
int main(){
BankRegister bankRegister;
map<string, function<bool (string)>> commands;
using std::placeholders::_1;
commands.emplace("create_bank",std::bind(create_bank, _1, std::ref(bankRegister)));
You can do the same thing with a lambda function:
commands.emplace("create_bank", [&bankRegister](const string& args) { return create_bank(args, bankRegister); });
The function object returned by bind
and the closure object created by the lambda expression both have the required call signature, bool(const string&)
, but they also contain a reference to the bankRegister
object and can pass it to create_bank
回答2:
Just use fancy code here:
#include <functional>
#include <string>
#include <map>
struct BankRegister {
void create_bank(const std::string& name);
};
void handle_new_bank(BankRegister* reg, const std::string& name) {
reg->create_bank(name);
}
int main() {
std::map<std::string, std::function<void (const std::string)> > cmds;
BankRegister reg;
cmds.emplace("new_bank", std::bind(&handle_new_bank, ®, std::placeholders::_1));
}
来源:https://stackoverflow.com/questions/33963808/parsing-commands-using-mapconst-string-function-commands