【问题标题】:Simple text menu in C++C++ 中的简单文本菜单
【发布时间】:2010-09-22 08:57:56
【问题描述】:

我正在用 C++ 编写一个愚蠢的小应用程序来测试我的一个库。我希望应用程序向用户显示命令列表,允许用户键入命令,然后执行与该命令关联的操作。听起来很简单。 在 C# 中,我最终会编写一个命令列表/映射,如下所示:

    class MenuItem
    {
        public MenuItem(string cmd, string desc, Action action)
        {
            Command = cmd;
            Description = desc;
            Action = action;
        }

        public string Command { get; private set; }
        public string Description { get; private set; }
        public Action Action { get; private set; }
    }

    static void Main(string[] args)
    {
        var items = new List<MenuItem>();

        items.Add(new MenuItem(
            "add",
            "Adds 1 and 2",
            ()=> Console.WriteLine(1+2)));
    }

关于如何在 C++ 中实现这一点有什么建议吗?我真的不想为每个命令定义单独的类/函数。我可以使用 Boost,但不能使用 TR1。

【问题讨论】:

    标签: c++ text lambda menu closures


    【解决方案1】:

    一种非常常见的技术是使用函数指针或 boost::function,由项目名称索引,或者通过具有它们的向量并按项目索引进行索引。使用项目名称的简单示例:

    void exit_me(); /* exits the program */
    void help(); /* displays help */
    
    std::map< std::string, boost::function<void()> > menu;
    menu["exit"] = &exit_me;
    menu["help"] = &help;
    
    std::string choice;
    for(;;) {
        std::cout << "Please choose: \n";
        std::map<std::string, boost::function<void()> >::iterator it = menu.begin();
        while(it != menu.end()) {
            std::cout << (it++)->first << std::endl;
        }
    
        std::cin >> choice;
        if(menu.find(choice) == menu.end()) {
            /* item isn't found */
            continue; /* next round */
        }   
    
        menu[choice](); /* executes the function */
    }
    

    C++ 还没有 lambda 特性,所以很遗憾,你真的必须使用函数来完成这项任务。您可以使用 boost::lambda,但请注意它只是模拟 lambda,远不如原生解决方案强大:

    menu["help"] = cout << constant("This is my little program, you can use it really nicely");
    

    注意常量(...)的使用,否则 boost::lambda 不会注意到这应该是一个 lambda 表达式:编译器会尝试使用 std::cout 输出字符串,然后赋值菜单[“帮助”]的结果(一个 std::ostream 引用)。你仍然可以使用 boost::function,因为它会接受所有返回 void 并且不带参数的东西——包括函数对象,这是 boost::lambda 创建的。

    如果你真的不想要单独的函数或 boost::lambda,你可以打印出一个包含项目名称的向量,然后在用户给出的项目编号上 switch。这可能是最简单、最直接的方式。

    【讨论】:

    • 关闭,但我仍然需要定义单独的函数 exit_me() 和 help()... 还有其他方法吗?
    • 谢谢。我将坚持使用单独的函数并等待 TR1 的 lambda 被纳入标准。
    • lambdas 将成为下一个 c++ 的新语言特性。您将能够执行 menu["help"] = []() { cout
    • 有个小错误,应该有std::cout
    【解决方案2】:

    为什么不直接将 C# 代码移植到 C++?有一些工作要做,但这样的事情应该可以让你完成大部分工作:

    using std::string;
    class MenuItem    
    {        
        public:
            MenuItem(string cmd, string desc, boost::function<bool()> action):Command(cmd),
                                                                              Description(desc),
                                                                              Action(action) 
            {}
            boost::function<bool()> GetAction() { return Action; }
            string GetDescription() { return Description; }
            string GetCommand() { return Command; }
        private:
            string Command;
            string Description;
            boost::function<bool()> Action;
    }
    

    定义后,您的 main() 可以使用 std::list,并使用简单的 while() 循环检查 MenuItem 的 Action 的退出值以确定它是否应该退出。

    【讨论】:

    • MenuItem 不是这里的问题。这是缺少 lambda 或闭包。在今天的 C++ 中,我必须为每个命令定义单独的函数(boost::function 将“指向”它们),而不是在一个地方完成所有操作。查看 litb 的 cmets。
    猜你喜欢
    • 2017-07-14
    • 1970-01-01
    • 2012-01-15
    • 1970-01-01
    • 2021-11-07
    • 2016-03-24
    • 2019-08-02
    • 2012-08-29
    • 2013-11-15
    相关资源
    最近更新 更多