2012-02-08 20 views
40

Me gustaría crear una clase donde el cliente pueda almacenar una expresión lambda como []() -> void {} como un campo de la clase, pero no puedo encontrar la manera de hacerlo. One answer suggested using decltype, que probé sin éxito. Aquí hay un ideone source link. El siguiente es el origen y el resultado:¿Cómo puedo almacenar una expresión lambda como un campo de una clase en 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"); 
    }); 
} 

Resultado:

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&) 

¿Alguien sabe cómo hacer esto?

+5

Cada lambda crea su propio tipo único. En 'auto A = []() {}; auto B = []() {}; '' A' y 'B' no son del mismo tipo. – bames53

+1

Desafortunadamente 'struct A {auto x = 0; }; 'no está permitido. –

Respuesta

40

Si desea que un miembro de clase sea una expresión lambda, considere usar el tipo de envoltorio std::function<> (del encabezado <functional>), que puede contener cualquier función invocable. Por ejemplo:

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

De esta forma, no es necesario que conozca el tipo de expresión lambda. Solo puede almacenar un std::function<> del tipo de función apropiado, y el sistema de la plantilla manejará todos los tipos por usted. De manera más general, cualquier entidad invocable con la firma adecuada se puede asignar a std::function<>, incluso si el tipo real de ese functor es anónimo (en el caso de lambdas) o realmente complicado.

El tipo dentro de la plantilla std::function debe ser el tipo de función correspondiente a la función que desea almacenar. Por lo tanto, por ejemplo, para almacenar una función que toma dos int sy devuelve vacía, haría un std::function<void (int, int)>. Para una función que no requiere parámetros y devuelve int, usaría std::function<int()>. En su caso, ya que desea una función que no toma parámetros y devuelve void, te gustaría algo como esto:

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. 
} 

Espero que esto ayude!

+0

Pregunta: ¿'-> vacío 'es realmente necesario aquí? Sé que la cláusula de devolución puede omitirse (y así deducirse) en varias circunstancias, y esto me parece muy fácil (no 'return'). –

+0

@ MatthieuM.- ¡En realidad no estoy seguro! Tenía la impresión de que tenía que tenerlo, pero si me equivoco, me gustaría actualizar esta respuesta. – templatetypedef

+0

Bueno, yo también estoy aprendiendo, así que esperaba * que * lo supieras :) –

7

La única manera que puedo pensar para almacenar una lambda en una clase es utilizar una plantilla con una función de ayuda make_:

expresión
#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

evita la necesidad de especificar argumentos de plantilla mediante la introducción de este helper 'make_myclass'. Esa es la [expresión idiomática del generador de objetos] (https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Object_Generator). – mucaho

Cuestiones relacionadas