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.
source to share
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.
source to share
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.
source to share