Простое текстовое меню в C ++ - PullRequest
0 голосов
/ 14 ноября 2008

Я пишу маленькое глупое приложение на 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.

Ответы [ 2 ]

6 голосов
/ 14 ноября 2008

Очень распространенным методом является использование указателей на функции или 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 ++ пока нет лямбда-функции, поэтому вам, к сожалению, действительно нужно использовать функции для этой задачи. Вы можете использовать boost :: lambda, но имейте в виду, что он просто имитирует лямбды и далеко не так мощен, как собственное решение:

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

Обратите внимание на использование константы (...), так как иначе boost :: lambda не заметит, что это должно быть лямбда-выражение: компилятор попытается вывести строку, используя std :: cout, и назначит результат (ссылка std :: ostream) на menu ["help"]. Вы все еще можете использовать boost :: function, так как он будет принимать все, возвращающее void и не принимая никаких аргументов, включая объекты-функции, которые и создает boost :: lambda.

Если вам действительно не нужны отдельные функции или boost :: lambda, вы можете просто распечатать вектор имен элементов, а затем switch на номере элемента, заданном пользователем. Это, вероятно, самый простой и прямой способ сделать это.

0 голосов
/ 14 ноября 2008

Почему бы просто не перенести код 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, чтобы определить, должен ли он выйти.

...