0

ライブラリの 1 つをテストするために、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 は使えません。

4

2 に答える 2

7

非常に一般的な手法は、アイテム名でインデックス付けされた関数ポインター、または 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 を使用して文字列を出力しようとし、結果 ( menu["help"] への std::ostream 参照)。boost::function は引き続き使用できます。これは、boost::lambda が作成する関数オブジェクトを含め、void を返し、引数を取らないものすべてを受け入れるためです。

個別の関数やboost::lambdaが本当に必要ない場合は、アイテム名のベクトルを出力してからswitch、ユーザーが指定したアイテム番号を取得できます。これはおそらく最も簡単で簡単な方法です。

于 2008-11-14T15:52:47.217 に答える
0

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 を使用し、MenuItem の Action の終了値をチェックして終了するかどうかを判断する単純な while() ループを使用できます。

于 2008-11-14T16:19:49.253 に答える