2017-07-26 3 views
1

これはコードの密接な問題です。これは既に例があります。私はコードでこの1トンをやっているし、これらのすべてのラムダ(いくつかは同じもの)の作成は私にうっとりさせ始めた。構造体のコンテナからフィールドを合計する必要があります

ので、構造体の与えられた:私はそれらへのポインタのコンテナを持って

struct foo { 
    int b() const { return _b; } 
    int a() const { return _a; } 
    int r() const { return _r; } 
    const int _b; 
    const int _a; 
    const int _r; 
}; 

を、今私は、コンテナを通過し、フィールドのいずれかの合計を取得したい、のはvector<foo*> foosを言わせて。一例として、
私はフィールド_rを望んでいた場合は、その後、私の現在のアプローチは、これを行うことです。

accumulate(cbegin(foos), cend(foos), 0, [](const auto init, const auto i) { return init + i->r(); }) 

私はどこでも、この行を書いています。これを改善することはできますか?私は本当にこのようなものを書いています:

私は標準がそういうものを提供しているとは思いません。私は明らかにそれを書くことができましたが、読者は疑問のコードを理解するために、accumulateのことを知るだけでなく、

+0

私は小さなユーティリティ機能を提供するとの問題が表示されません。時には、標準ライブラリにあるものについての情報も参照する必要があります。すべてそれを心から知っている人はほとんどいません。それがきれいに書かれ、アクセス可能な限り、標準ライブラリに抽象化を追加してみませんか? – StoryTeller

+0

@StoryTeller今私はそれにも傾いています。この質問は、私がそれをやる前に私の最後のストップです、ちょうど良い方法があるように感じます。 –

+1

あなたはクラスメソッドを考えましたか?静的void foo :: acc4(std :: vector foos)? –

答えて

1

に導入されたVariable Templatesを使用して、これを解決する実際にはエレガントな方法があります。場所にラムダを書き出すと同じ効果を持つことになります

template <int (foo::*T)()> 
auto func = [](const auto init, const auto i){ return init + (i->*T)(); }; 

accumulateに最後の引数としてfuncfunc適切な専門を渡す:私たちは、テンプレート引数としてメソッドポインタを使用してラムダ変数をテンプレート化することができます

accumulate(cbegin(foos), cend(foos), 0, func<&foo::r>) 

Live Example


オフに基づいて別の代替

template <int (foo::*T)()> 
int func(const int init, const foo* i) { return init + (i->*T)(); } 

、単にメソッドポインタ渡すことによって使用することができます:

accumulate(cbegin(foos), cend(foos), 0, &func<&foo::r>) 

Live Example


を必要としない同じtemplatizationの前提は、テンプレート化機能suggested by StoryTellerです両方の例で必要とされる特異性はで削除されました。ここではテンプレートパラメータの種類の:http://en.cppreference.com/w/cpp/language/autoこれだけではなく、私たちはそれがことにより、任意のクラスを使用することができますfuncを宣言できるようfooます:

template <auto T> 
auto func(const auto init, const auto i) { return init + (i->*T)(); } 
+0

@StoryTeller概念は理にかなっているようです。私は私の答えを更新し始めましたが、何らかの理由でテンプレート化された関数のアドレスを 'accumulate'に渡すことができません:http://ideone.com/WTfxQR私はこれが正当であると確信しています:https:// stackoverflow。 com/q/38402133/2642059私はここで何が間違っていますか? –

+1

[メンバーへのポインタのconst修飾子が見つかりませんでした](http://ideone.com/FhrIlc)。私の投稿を削除したのは、C++ 98のソリューションが一般的なラムダほど堅牢ではないからです(あなたの例題は型の命名によって実証されています)。 – StoryTeller

+0

@StoryTellerありがとう、私は何かを逃したことを知っていた。 C++ 17では、私たちはもう少し先に進んで、このような間違いを避けています: 'template auto func(const auto init、const auto i){return init +(i - > * T)(); } ' –

1

カスタム累積を書く代わりに、std::accumulateの引数として使用できるファンクタを返すカスタムファンクションジェネレータを作成することをお勧めします。

template<class Fun> 
auto mem_accumulator(Fun member_function) { 
    return [=](auto init, auto i) { 
     return init + (i->*member_function)(); 
    }; 
} 

次いで

accumulate(cbegin(foos), cend(foos), 0, mem_accumulator(&foo::r)); 

いくつかのバリエーション:オブジェクトのコンテナの

template<class MemFun> 
auto mem_accumulator(MemFun member_function) { 
    return [=](auto init, auto i) { 
     return init + (i.*member_function)(); 
    }; 
} 

使用データメンバポインタの代わりに機能:

をむしろ、メンバ関数ポインタよりもの
template<class T> 
auto mem_accumulator(T member_ptr) { 
    return [=](auto init, auto i) { 
     return init + i->*member_ptr; 
    }; 
} 
// ... 
accumulator(&foo::_r) 

サポートファンクタ、:

template<class Fun> 
auto accumulator(Fun fun) { 
    return [=](auto init, auto i) { 
     return init + fun(i); 
    }; 
} 
// ... 
accumulator(std::mem_fun(&foo::r)) 

これらの変化のいくつかは(?すべて)、おそらくいくつかのSFINAEの魔法で自動的に選択されるように組み合わせることができるが、それは複雑になります。

関連する問題