2011-09-19 7 views
70

私はラムダのベクトルを作成しようとしているが、失敗しました:それはcompiles fine、ライン#2までC++ 11で(同じタイプの)ラムダのベクトルを作成できないのはなぜですか?

auto ignore = [&]() { return 10; }; //1 
std::vector<decltype(ignore)> v;  //2 
v.push_back([&]() { return 100; }); //3 

を。しかし、ライン#3は、compilation errorを与える:

error: no matching function for call to 'std::vector<main()::<lambda()>>::push_back(main()::<lambda()>)'

私は、関数ポインタまたは関数オブジェクトのベクトルのベクトルを望んでいません。しかし、実際のラムダ式をカプセル化した関数オブジェクトのベクトルは、私のために働くでしょう。これは可能ですか?

+21

"関数ポインタのベクトルまたは関数オブジェクトのベクトルは必要ありません。"しかし、それはあなたが求めていたものです。ラムダ**は**関数オブジェクトです。 –

+0

密接に関連しています:[C++ 11で "auto"で推測するとラムダの種類は何ですか?](http://stackoverflow.com/q/7951377/514235) – iammilind

答えて

112

すべてのラムダは、同一の署名を持っていても、 —という異なるタイプのを持っています。そのようなことをしたい場合は、std::functionのような実行時カプセル化コンテナを使用する必要があります。

例えば:

std::vector<std::function<int()>> functors; 
functors.push_back([&] { return 100; }); 
functors.push_back([&] { return 10; }); 

I don't want a vector of function pointers or vector of function objects.

まあ、私はすべての私の夢を開発する百人の開発チームとの素敵な高給の仕事をしたいと思いますが、それはどちらか、起こるつもりはありません。あなたはいつもあなたが望むものを得ることはできません。

+51

百人の開発チームを管理することは、より悪夢のような私には聞こえる:) –

+10

また、([]スタイル)関数ポインタに分解できることcapturelessのラムダを忘れないでください。そのため、同じタイプの関数ポインタの配列を格納することができました。 VC10はそれをまだ実装していないことに注意してください。 –

+0

ところで、とにかくこれらの例ではキャプチャレスを使用しないでください。それとも必要ですか? - ところで、関数ポインタへのキャプチャレスラムダはVC11でサポートされているようです。しかし、それをテストしていない。 – Klaim

36

すべてのラムダ式は、文字ごとに同じであっても、の異なる型を持っています。。あなたは別の型のラムダをベクタにプッシュしていますが、それは明らかに動作しません。

One solutionの代わりにstd::function<int()>のベクトルを作ることです。別のノートで

auto ignore = [&]() { return 10; }; 
std::vector<std::function<int()>> v; 
v.push_back(ignore); 
v.push_back([&]() { return 100; }); 

、それはあなたが何をキャプチャしていないとき[&]を使用することはお勧めできません。

+8

引数を取らないラムダに '()'は必要ありません。 – Puppy

12

ラムダがステートレスである場合、つまり[](...){...}の場合、C++ 11では関数ポインタに分解されます。理論的には、C++ 11対応のコンパイラはこれをコンパイルすることができるだろう:

auto ignore = []() { return 10; }; //1 note misssing & in []! 
std::vector<int (*)()> v;  //2 
v.push_back([]() { return 100; }); //3 
+3

レコード 'auto ignore = * [] {return 10; }; 'は' int(*)() 'を無視します。 –

+0

@Luc、ああ、それは総額です!彼らはいつそれを追加しましたか? – MSN

+2

さて、最初に関数ポインタを取ることを可能にする変換関数は '明示的ではない 'ことを要求されているので、ラムダ式の逆参照は有効であり、変換の結果としてポインタを逆参照します。その後、 'auto'を使うことでその参照をポインタに戻します。 ( 'auto&'または 'auto && 'を使うと参照が保持されます) –

17

関連性があるものを他の人が言っている、それは非常に有用ではないのですが、宣言し、ラムダのベクトルを使用することは可能ですが:

auto lambda = [] { return 10; }; 
std::vector<decltype(lambda)> vector; 
vector.push_back(lambda); 

だから、あなたは、それがlambdaのコピー/移動だとして、そこにラムダの任意の番号を保存することができます!

+0

プッシュバックが異なるパラメータを持つループ内で発生する場合に実際に役立つ可能性があります。おそらく遅延評価目的のためです。 – MaHuJa

+6

いいえ、関数オブジェクトだけのベクトルにパラメータを入れないでください。同じラムダのすべてのコピーを持つベクトルになります – hariseldon78

2

各ラムダは異なるタイプです。 std::vectorの代わりにstd::tupleを使用する必要があります。

2

あなたは(ナワズによって提案された修正で更新)ラムダ生成機能を使用できます。

#include <vector> 
#include <iostream> 

int main() { 
    auto lambda_gen = [] (int i) {return [i](int x){ return i*x;};} ; 

    using my_lambda = decltype(lambda_gen(1)); 

    std::vector<my_lambda> vec; 

    for(int i = 0; i < 10; i++) vec.push_back(lambda_gen(i)); 

    int i = 0; 

    for (auto& lambda : vec){ 
     std::cout << lambda(i) << std::endl; 
     i++; 
    } 
} 

しかし、私はあなたが基本的には、この時点で独自のクラスを作ったと思います。そうでなければ、ラムダが完全に異なるcaputres/argsなどを持っている場合は、おそらくタプルを使用する必要があります。

+0

これは 'lambda_gen'のような関数でラップすることができます。ラムダそのもの。しかし、 'auto a = lambda_gen(1);'は不要な呼び出しを行います。これは、 '' decltype(lambda_gen(1)) '(http://coliru.stacked-crooked.com/a/27c315671c196a56)。 – Nawaz

+0

それでも余分な電話がかかりますか?また別の副次的な点は、C++ 11で、私が思う関数に末尾の戻り値の型を追加する必要があるということです。 – antediluvian

+0

いいえ、 'decltype'の中にあるものは*評価されていない*なので、実際には呼び出されません。 'sizeof'と同じです。また、このコードはC++ 11では動作しません。 – Nawaz

関連する問題