web-dev-qa-db-fra.com

Comment puis-je stocker une expression lambda en tant que champ d'une classe en C ++ 11?

Je voudrais créer une classe où le client peut stocker une expression lambda comme []() -> void {} comme champ de la classe, mais je ne sais pas comment le faire. ne réponse a suggéré d'utiliser decltype , que j'ai essayé sans succès. Voici un lien source ideone . Ce qui suit est la source et le résultat:

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

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

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

Résultat:

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

Est-ce que quelqu'un sait comment faire ça?

44
user34537

Si vous voulez qu'un membre de la classe soit une expression lambda, pensez à utiliser le type d'encapsuleur std::function<> (De l'en-tête <functional>), Qui peut contenir n'importe quelle fonction appelable. Par exemple:

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

De cette façon, vous n'avez pas besoin de connaître le type de l'expression lambda. Vous pouvez simplement stocker un std::function<> Du type de fonction approprié, et le système de modèles gérera tous les types pour vous. Plus généralement, toute entité appelable de la signature appropriée peut être affectée à un std::function<>, Même si le type réel de ce foncteur est anonyme (dans le cas des lambdas) ou vraiment compliqué.

Le type à l'intérieur du modèle std::function Doit être le type de fonction correspondant à la fonction que vous souhaitez stocker. Ainsi, par exemple, pour stocker une fonction qui prend deux int et retourne void, vous feriez une std::function<void (int, int)>. Pour une fonction qui ne prend aucun paramètre et renvoie un int, vous utiliseriez std::function<int()>. Dans votre cas, puisque vous voulez une fonction qui ne prend aucun paramètre et retourne void, vous voudriez quelque chose comme ceci:

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

J'espère que cela t'aides!

48
templatetypedef

La seule façon de penser à stocker un lambda dans une classe est d'utiliser un modèle avec une aide make_ une fonction:

#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");
    });
}
9
cubuspl42