2012-01-24 7 views
1

メニューツールバーのすべての要素を処理する多くの機能を持つアプリケーションがあります。私はこの実装を変更します、またはメニューは、サブメニューを持つことができ可変長の関数ポインタにインライン関数またはC++のMACROSを使う方が良い

subMenuDefaultMenuShortcuts(ui->fileMenu); 
subMenuDefaultMenuShortcuts(ui->editMenu); 
subMenuDefaultMenuShortcuts(ui->windowMenu); 
subMenuDefaultMenuShortcuts(ui->helpMenu); 

subMenuUpdateLabels(ui->fileMenu,hierarchy); 
subMenuUpdateLabels(ui->editMenu,hierarchy); 
subMenuUpdateLabels(ui->windowMenu,hierarchy); 
subMenuUpdateLabels(ui->helpMenu,hierarchy); 

ことが可能です:

のコードは次のようなもののように見えます。したがって、コードの検索と置き換えは、醜いだけでなく、読みにくく、エラーを起こしやすくなります。ので、私のコードは次のようになりwhould

OnAllMenus(functionName,params ...) 

理想的に私はこのような何かをしたいwhould

OnAllMenus(subMenuUpdateLabels) 
OnAllMenus(subMenuUpdateLabels,hierarchy) 
OnAllMenus(someFunction,hierarchy,argument1,argument2) 

私はマクロを使用していたが、その使用は推奨されません。 関数のポインタでインライン関数を使用するHowerverは、ほとんど読みにくいコードにつながっているようです。 (そして関数の引数の数が変わることを期待している関数ポインタの例は見られませんでした)。

addindを実行しないと、それほど複雑ではない複雑なコードを作成することはできません。

+0

また、メニューへのメンバポインタのローカル配列を作成し、それを反復処理することもできます。それは繰り返しをなくし、コードのエラーを起こしにくくします。または、より単純な記述では、参照によってメニューを取得する関数は、そのメニューのすべての操作を実行した後、単一の関数でロジックを持ちます。呼び出し元のメニューリストは、より難しいメンバポインタを使用する必要はありません読み込み/維持する。 –

答えて

1
template<typename FuncPointer, typename ... Args> 
void for_all_menus(FuncPointer func, Args ... args) 
{ 
    f(ui->foo,std::forward<Args>(args)...); 
    f(ui->bar,std::forward<Args>(args)...); 
    // etc 
} 

// use 
for_all_menus(&subMenuLabel, hierarchy); 

Pmrをの答えが、どこでも散乱される愚かboost::bind秒を停止する可変長引数テンプレート。

+0

'std :: forward'を使う必要がありますこの仕事を完璧にするしかし確かに私のファンクタよりもきれいです。 – pmr

+1

これはC++ 11コンパイラを必要とします。それが利用可能な場合、これは最もクリーンな解決策です。ブーストバインドでこの解決策が複雑ではないはずです(最初のテンプレート(4行)とそれぞれのバインドされた関数(1行、彼の答えの問題は、より多くの選択肢を提供する上で、彼は答えをあまりにも複雑にしているということです。 –

+0

はLinuxで動作しますが、まだセットアップしていないWindowsとMac環境でテストしなければなりません。 – Anton

1

boost::functionboost::bindを使用できます。あなたは、単にboost::functionとる関数と機能 テンプレートを置き換える、よりダイナミックなものが必要な場合は

template<typename Func> 
void for_all_menus(Func f) { 
    f(ui->foo); 
    f(ui->bar); 
    // etc 
} 

// use 
for_all_menus(boost::bind(subMenuLabel, _1, hierarchy)); 

// with variadic templates 
template<typename Func, typename Args...> 
struct for_all_menus { 
    Func f; 
    void operator()(Args&&... args) { 
    // umh, I always mess up the syntax 
    // you might want to double check this 
    f(ui->foo, std::forward<Args>(args)...); 
    } 
}; 
template<typename F> 
for_all_menus<F> make_for_all_menus(F f) { return for_all_menus<F>{f}; } 

// use 
auto f = make_for_all_menus(subMenuLabel); 
f(hierarchy); 

。もちろん でもC++ 11の同等物とlambdaを使うことができます。

メニューのリストを1か所にまとめて、別の場所でそのリスト を使用する場合は、Boost.Preprocessorをお勧めします。しかし、 はそれに頼る前に2度考えてもいいかもしれません。

+0

booster :: bindからのファンクタの作成を避けるためにバリデーショナルテンプレートを使用できることに注意してください。しかし、同じ一般的なアイデア。 – Lalaland

+0

@EthanSteinberg確かに。追加されます。 – pmr

+0

2つのアプローチのうち、最も簡単なのはバインドです。コードをもっと単純にするつもりでない限り(他の答えと同じように)、新しい機能を使うだけの理由はありません...このバリデーショナルテンプレートを使ったアプローチは狂気です –

関連する問題