使用map <const string,=“”function <?=“”(?)=“”>&gt;解析命令命令;

时间:2015-11-27 19:32:27

标签: c++ function c++11 dictionary variadic-functions

问题陈述:

给定交互式输入,在适当的对象(Bank,BankRegister,BasicAccount等)上调用适当的方法。

输入(每个命令在一个单独的行上):

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...

建议的解决方案:

#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);
    ...
}

为什么不起作用

  1. 无法从函数中访问bankRegister对象。我可以通过不断引用函数来传递它,但只有一些函数需要它。我想让它的成员(m_banks,m_next_bankNumber)保持静态,但是我必须将它们公之于众,这可能是一个糟糕的设计决定。
  2. 参数解析应该在哪里发生?这样可以吗?
  3. 返回值应代表什么?

    a)成功解析参数

    b)成功解析参数并成功执行命令

    我使用了一些错误的异常,但有些是沉默的,除了cerr。

  4. 我可以在这里使用可变参数函数来解析参数吗?

  5. 还有什么可以改进吗?

2 个答案:

答案 0 :(得分:2)

您可以更改create_bank函数的签名并使用std::bind绑定BankRegister参数,创建一个带有调用签名的函数对象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)));

你可以用lambda函数做同样的事情:

    commands.emplace("create_bank", [&bankRegister](const string& args) { return create_bank(args, bankRegister); });

bind返回的函数对象和lambda表达式创建的闭包对象都具有所需的调用签名bool(const string&),但它们也包含对bankRegister对象的引用,可以将其传递给create_bank

答案 1 :(得分:1)

在这里使用花哨的代码:

#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, &reg, std::placeholders::_1));
}