2012-02-08 13 views
40

私はクライアントがクラスのフィールドとして[]() -> void {}のようなラムダ式を格納することができるクラスを作成したいと思いますが、その方法を理解することはできません。 One answer suggested using decltype、私はそれを成功させようとしました。ここにはideone source linkがあります。下記のソースと結果である:ラムダ式をC++ 11のクラスのフィールドとして保存するにはどうすればよいですか?

#include <cstdio> 
auto voidLambda = []()->void{}; 

class MyClass { 
public: 
    decltype(voidLambda) t; 
    MyClass(decltype(voidLambda) t) { 
     this->t = t; 
    } 
}; 

int main() { 
    MyClass([] { 
     printf("hi"); 
    }); 
} 

結果:

prog.cpp: In constructor 'MyClass::MyClass(<lambda()>)': 
prog.cpp:3:79: error: no matching function for call to '<lambda()>::__lambda0()' 
prog.cpp:2:20: note: candidates are: <lambda()>::<lambda>(const<lambda()>&) 
prog.cpp:2:20: note:     <lambda()>::<lambda>(<lambda()>&&) 
prog.cpp:3:88: error: no match for 'operator=' in '((MyClass*)this)->MyClass::t = t' 
prog.cpp: In function 'int main()': 
prog.cpp:5:27: error: no matching function for call to 'MyClass::MyClass(main()::<lambda()>)' 
prog.cpp:3:48: note: candidates are: MyClass::MyClass(<lambda()>) 
prog.cpp:3:14: note:     MyClass::MyClass(const MyClass&) 

は誰もがこれを行う方法を知っていますか?

+5

すべてのラムダ式は、それ自身のユニークなタイプを作成します。 'auto A = [](){};では、 auto B = [](){}; '' A'と 'B'は同じ型ではありません。 – bames53

+1

残念ながら 'struct A {auto x = 0; }; 'は許されません。 –

答えて

40

クラスメンバーをラムダ式にする場合は、呼び出し可能な関数を保持できるstd::function<>ラッパータイプ(<functional>ヘッダー)を使用することを検討してください。例:

std::function<int()> myFunction = []() { return 0; } 
myFunction(); // Returns 0; 

このようにして、ラムダ式の型を知る必要はありません。適切な関数型のstd::function<>を格納すれば、テンプレートシステムがすべての型を処理します。より一般的には、そのファンクタの実際の型が匿名(lambdaの場合)または実際に複雑であっても、適切なシグネチャの任意の呼び出し可能なエンティティをstd::function<>に割り当てることができます。

std::functionテンプレート内のタイプは、保存する機能に対応する関数タイプである必要があります。たとえば、2つの文字を取り入れてvoidを返す関数を格納する場合は、std::function<void (int, int)>となります。パラメータを取らずにintを返す関数の場合は、std::function<int()>を使用します。あなたはパラメータを取らず、voidを返す関数をしたいので、あなたのケースでは、あなたはこのような何かをしたいと思います:

class MyClass { 
public: 
    std::function<void()> function; 
    MyClass(std::function<void()> f) : function(f) { 
     // Handled in initializer list 
    } 
}; 

int main() { 
    MyClass([] { 
     printf("hi") 
    }) mc; // Should be just fine. 
} 

ホープ、このことができます!

+0

質問:ここでは ' - > void'が本当に必要ですか?私は、復帰句がいくつかの状況で省略され(したがって推論される)ことができることを知っています。これは簡単なケース(「復帰」なし)を開始するように私を襲います。 –

+0

@ MatthieuM.-私は実際にはわかりません!私はあなたがそれを持っていなければならないという印象を受けていましたが、私が間違っていると、私はこの答えを更新することができました。 – templatetypedef

+0

まあ、私も学んでいるので、あなたが知りたいと思っていたのです。 –

7

私はクラスでラムダを保存すると考えることができる唯一の方法は、ヘルパーmake_機能付きテンプレートを使用することです:

#include <cstdio> 
#include <utility> 

template<class Lambda> 
class MyClass { 
    Lambda _t; 
public: 
    MyClass(Lambda &&t) : _t(std::forward<Lambda>(t)) { 
     _t(); 
    } 
}; 

template<class Lambda> 
MyClass<Lambda> make_myclass(Lambda &&t) { 
    return { std::forward<Lambda>(t) }; 
} 

int main() { 
    make_myclass([] { 
     printf("hi"); 
    }); 
} 
+4

は、このヘルパー 'make_myclass'を導入することによってテンプレート引数を指定する必要性を回避します。それは[Object generator idiom](https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Object_Generator)です。 – mucaho

関連する問題