Simple text menu in C ++

I am writing a silly little C ++ application to test one of my libraries. I would like the application to display a list of commands to the user, allow the user to enter a command, and then perform the action associated with that command. Sounds simple enough. In C # I would end up writing a list / map of commands like:

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

      

Any suggestions on how to achieve this in C ++? I really don't want to define separate classes / functions for each command. I can use Boost, but not TR1.

0


source to share


2 answers


A very common technique is to use function pointers or boost :: function indexed by element name or by vectoring them and indexing by element index for this job. Simple example using element name:

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 ++ doesn't have a lambda function yet, so you really need to use functions for this task, unfortunately. You can use boost :: lambda, but note that this just simulates lambdas and is nowhere more powerful than its own solution:



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

      

Note the use of the constant (...), because otherwise boost :: lambda would not notice that it must be a lambda expression: the compiler will try to output the string with std :: cout and assign the result (reference std :: ostream ) in the ["help"] menu. You can still use boost :: function, since it will accept all return voids and take no arguments, including function objects, which creates boost :: lambda.

If you don't really need separate functions or boost :: lambda, you can just print a vector of item names and then switch

by user-supplied item number. This is probably the easiest and most direct way to do it.

+6


source


Why not just move your C # code to C ++? There's a bit of work to be done, but something like this should get most of your work:

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

      



With that in mind, your main () can use std :: list and use a simple while () loop that checks the exit value for the MenuItem action to determine if it should exit.

0


source







All Articles