3

私は似たような種類のスレッドを見てきましたが、私の場合にソリューションを正確に適用する方法がわかりません。私の問題は、「A」、「B」、「C」などの一連のユースケースがあることです。渡された入力(2つのユースケースが入力)がリストされたユースケースのいずれか2つである場合に実行する必要がある特定のコマンドがあります。例えば:

switch(input1)
{
case A:
break;
case B:
break;
case C:
break;
}

それぞれのケースの中で、入力2をチェックする必要があるので、最終的なコードは次のようになります。

switch(input1)
{
case A:
{
switch(input2):
case B:
break;
case c:
break;
}
case B:
{
switch(input2):
case A:
break;
case c:
break;
}
....

}

(ペア、コマンド)のマップを使用して、このスイッチケースを削除することを考えていましたが、この問題を解決するための代替のより良い解決策または設計上の問題はありますか?

4

7 に答える 7

9

パフォーマンスがそれほど大きな問題ではない場合、関数ポインターのマップが 1 つの解決策になる可能性があります。

ラベルA, B, C... がより小さい小さな255整数値であると仮定します。

  • 最初にマップを設定します

    #define KEY(a,b)  ( (a<<8) | b )
    
    std::map<int, function_pointer_type>  dispatcher =
    {
        { KEY(A,B), ab_handler},
        { KEY(A,C), ac_handler},
        { KEY(B,C), bc_handler},
        //etc
    };
    
  • マップを使用して、入力セットごとに適切なハンドラーを呼び出します。

     dispatcher[KEY(input1,input2)] (/* args */);
    

可能な入力のペアごとにディスパッチャーをセットアップする必要があることに注意してください。KEY(A,B)また、とのペアKEY(B,A)が同じケースである場合、このケースを処理するために呼び出される関数を記述しinvokeて、残りのコードの使用方法を統一することができます。

 void invoke(int input1, int input2, /* args */)
 {
     if (dispatcher.find(KEY(input1, input2)) != dispatcher.end() )
           dispatcher[KEY(input1,input2)] (/* args */);
     else
           dispatcher[KEY(input2,input1)] (/* args */);
 }

次に、次のように使用します。

 invoke(input1, input2, /* args */);
 invoke(input2, input1, /* args */);  //still okay!

それが役立つことを願っています。

于 2013-02-12T08:12:30.650 に答える
2

あなたの場合、2 つのスイッチを 2 つの機能に分けてはどうでしょうか。

bool processInput2(char input2)
{
  switch(input2)
  {
   case 'A':
   {  
      // blah
   }
    break;
}

bool processInput1(char input1)
{
  switch(input1)
  {
   case 'A':
      processInput2(input2);
      break;
}
于 2013-02-12T08:05:52.530 に答える
1

1 つの可能性は、ネストされたケースごとにコードを 1 つの関数に分割することです。そのため、例には 6 つの関数があります。

void process_A_A() { ... }
void process_A_B() { ... }
void process_B_A() { ... }
void process_B_B() { ... }
void process_C_A() { ... }
void process_C_B() { ... }

次に、実行時の非常に高速な (一定時間の) 検索のために、初期化でそれらを配列に入れます。

typedef std::function<void(void)> Function;  // or: void (*)(void)
Function f[Input1Count][Input2Count];
f[A][A] = &process_A_A;
f[A][B] = &process_A_B;
...

適切な関数を呼び出すには、次のように記述します。

f[input1][input2]();

C++11std::function型を使用することにより、関数は従来の関数ポインターである必要がないことに注意してください。ラムダ関数またはファンクター オブジェクトにすることもできます。

一部のパーツを空のままにしたり、同じ機能を複数回割り当てたりすることもできます。一部のエントリを空のままにしておくことにした場合 (そのような場合は何もしないでください)、呼び出す前に関数オブジェクトを確認してください。

if (f[input1][input2])
    f[input1][input2]();
于 2013-02-12T08:21:09.657 に答える
0

あなたはいつでも次のようなことをすることができます:

switch ( 256 * input1 + input2 ) {
case 256 * 'A' + 'B':
    //  ...
    break;
//  ...
};

しかし、率直に言って、この場合、ネストされたスイッチの方が理解しやすいと思います。それがあなたの問題に対する正しい答えであると仮定します。switch文字入力の場合、多くの場合はそうですが、 などの他の代替手段がありますstd::map<std::pair<char, char>, Action const*>。ここActionで、 は仮想基本クラスであり、マップ内の各アクションは派生クラスの静的インスタンスです。これには、各アクションを別個のオブジェクトにするという利点があり (アクションで何を行うかによっては、利点ではない場合があります)、マップが動的に読み込まれる場合 (たとえば、のコンストラクターでAction)、アクションを追加せずにアクションを追加できます。パーサーのソースコードを変更します (ただし、この柔軟性は必要ないかもしれません)。

于 2013-02-12T08:45:31.867 に答える
0

関数を処理するためのマップまたはポインターのテーブルを使用した提案された回答は問題ありません。ただし、2 つの欠点があります。1) 手動で入れ子になったスイッチと比較して、パフォーマンスがわずかに低下します。2) ケース処理メソッドは完全に自己記述的ではありません。つまり、各ハンドル メソッドについて、その定義とマップを開始する場所で 2 回言及する必要があります。

2 つの選択肢があると思います。1) ソース コードの生成。ある種の表現からネストされたスイッチを自動的に生成します。ええと...このような小さなタスクにコード生成を追加することを気にしないのであれば、最適なコードを作成するのは非常に良いオプションです。2) プリプロセッサ ハックの使用。最もエレガントではありませんが、それを機能させるための非常に興味深い方法です。

まず、列挙型の X-Macroを宣言します。

#define ELEMENTS(processor) \
processor(firstElement)     \
processor(secondElement)    \
processor(thirdElement)

これを使用して、列挙型自体を宣言できます。

#define ENUM_PROCESSOR(arg) arg,

enum class
{
    ELEMENTS(ENUM_PROCESSOR)
};

#undef ENUM_PROCESSOR
Now we can add method that uses macros to generate nested switches:

void processElements(const Elements element1,
                     const Elements element2)
{
    // These macros are useful to trick the preprocessor to allow recursive macro calls
    // https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms
    #define EMPTY(...)
    #define DEFER(...) __VA_ARGS__ EMPTY()
    #define EXPAND(...) __VA_ARGS__
    #define ELEMENTS_INT() ELEMENTS

    #define PROCESS_NESTED_ENUM_VALUE(value)                                         \
    case Elements::value:                                                            \
    {                                                                                \
        process<Value1, Elements::value>();                                          \
        break;                                                                       \
    }

    #define PROCESS_ENUM_VALUE(value)                                                \
    case Elements::value:                                                            \
    {                                                                                \
        constexpr Elements Value1 = Elements::value;                                 \
        switch (element2)                                                            \
        {                                                                            \
            DEFER(ELEMENTS_INT)()(PROCESS_NESTED_ENUM_VALUE)                         \
        };                                                                           \
                                                                                     \
        break;                                                                       \
    }

    switch (element1)
    {
        EXPAND(ELEMENTS(PROCESS_ENUM_VALUE));
    };

    #undef EMPTY
    #undef DEFER
    #undef EXPAND

    #undef ELEMENT_TYPES_INT
    #undef PROCESS_ENUM_VALUE
    #undef PROCESS_NESTED_ENUM_VALUE
}

ここでは、プリプロセッサを「だまして」ELEMENTS を再帰的に展開するために多くの努力が払われています。主なアイデアはここでよく説明されています。

次に、ハンドラーをテンプレート関数の特殊化として宣言します。

template <Elements Element1, Elements Element2>
void process();

template<>
void process<Elements::firstElement, Elements::firstElement>()
{
    //some code 1;
}

...
于 2016-02-09T16:31:12.483 に答える
-1

if ブランチャーを使用しないのはなぜですか?

if (input1 == A && input2 == B) {
} else if (input1==A && input2 = C) {
} ...

これはあなたが言いたいことを書いているようなものです。

于 2013-02-12T08:09:19.990 に答える