【问题标题】:Parsing commands using map<const string, function<? (?)>> commands;使用 map<const string, function<? 解析命令(?)>> 命令;
【发布时间】:2015-11-27 19:32:27
【问题描述】:

问题陈述:

给定交互式输入,在适当的对象(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. 您还有其他需要改进的地方吗?

【问题讨论】:

  • 你的意思可能是commands[command](arguments),没有引号。
  • The bankRegister object can't be accessed from the functions. 所以把它作为一个额外的参数传入。或者,使命令成为其成员函数,并将指向成员的指针存储在映射中。
  • @IgorTandetnik 当然。已更正。
  • @IgorTandetnik 我可以通过额外的参数传递它,但只有一些函数需要它。必须修改其他的以采用他们不会使用的参数。我无法更改 BankRegister 的实现。
  • 哪些功能可以不用它?示例中的所有命令显然都需要一些代表所有可用银行、账户等的数据结构。 BankRegister 是那个结构,不是吗?

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


【解决方案1】:

您可以更改create_bank 函数的签名并使用std::bind 绑定BankRegister 参数,创建一个调用签名为bool(const string&amp;) 的函数对象

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&amp;),但它们还包含对 bankRegister 对象的引用,并且可以将其传递给 @987654330 @

【讨论】:

  • 美丽。为什么我必须使用std::ref(bankRegister) 而不是&amp;bankRegister
  • 因为我把create_bank改成引用BankRegister,所以需要传递一个引用。如果您使用&amp;bankRegister,那么它会传递一个指针,因此编译失败。如果您将 create_bank 更改为采用指针而不是引用(正如 SergeyA 在他的回答中所做的那样),那么您将使用 &amp;bankRegister 作为参数。基本上你需要根据create_bank 的声明方式传递正确的东西。
  • 接受 lambda 建议。
【解决方案2】:

在这里使用花哨的代码:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-26
    • 2015-04-30
    • 1970-01-01
    • 2010-11-27
    • 2011-09-24
    • 1970-01-01
    相关资源
    最近更新 更多