web-dev-qa-db-fra.com

C ++ 11 lambda comme variable membre?

Les lambda peuvent-ils être définis comme des membres de la classe?

Par exemple, serait-il possible de réécrire l'exemple de code ci-dessous en utilisant un lambda au lieu d'un objet fonction?

struct Foo {
    std::function<void()> bar;
};

La raison pour laquelle je me demande c'est parce que les lambda suivants peuvent être passés comme arguments:

template<typename Lambda>
void call_lambda(Lambda lambda) // what is the exact type here?
{ 
    lambda();
}

int test_foo() {
    call_lambda([]() { std::cout << "lambda calling" << std::endl; });
}

J'ai pensé que si un lambda peut être passé en tant qu'argument de fonction, alors peut-être qu'ils peuvent également être stockés en tant que variable membre.

Après plus de bricolage, j'ai trouvé que cela fonctionne (mais c'est un peu inutile):

auto say_hello = [](){ std::cout << "Hello"; };
struct Foo {
    typedef decltype(say_hello) Bar;
    Bar bar;
    Foo() : bar(say_hello) {}
};
44
StackedCrooked

Les modèles le permettent sans effacement de type, mais c'est tout:

template<typename T>
struct foo {
    T t;
};

template<typename T>
foo<typename std::decay<T>::type>
make_foo(T&& t)
{
    return { std::forward<T>(t) };
}

// ...
auto f = make_foo([] { return 42; });

Répéter les arguments que tout le monde a déjà exposés: []{} N'est pas un type, vous ne pouvez donc pas l'utiliser comme par exemple un paramètre de modèle comme vous essayez. L'utilisation de decltype est également douteuse car chaque instance d'une expression lambda est une notation pour un objet de fermeture séparé avec un type unique. (par exemple, le type de f ci-dessus est pasfoo<decltype([] { return 42; })>.)

17
Luc Danton

Un lambda crée simplement un objet fonction, donc, oui, vous pouvez initialiser un membre de fonction avec un lambda. Voici un exemple:

#include <functional>
#include <cmath>

struct Example {

  Example() {
    lambda = [](double x) { return int(std::round(x)); };
  };

  std::function<int(double)> lambda;

};
38
wjl

Un peu tard, mais je n'ai vu cette réponse nulle part ici. Si le lambda n'a pas d'arguments de capture, il peut être implicitement converti en un pointeur vers une fonction avec les mêmes arguments et types de retour.

Par exemple, le programme suivant compile correctement et fait ce que vous attendez:

struct a {
    int (*func)(int, int);
};

int main()
{
    a var;
    var.func = [](int a, int b) { return a+b; };
}

Bien sûr, l'un des principaux avantages de lambdas est la clause de capture, et une fois que vous l'ajoutez, cette astuce ne fonctionnera tout simplement pas. Utilisez std :: function ou un modèle, comme indiqué ci-dessus.

13
Shachar Shemesh
#include <functional>

struct Foo {
    std::function<void()> bar;
};

void hello(const std::string & name) {
    std::cout << "Hello " << name << "!" << std::endl;
}

int test_foo() {
    Foo f;
    f.bar = std::bind(hello, "John");

    // Alternatively: 
    f.bar = []() { hello("John"); };
    f.bar();
}
10
Alexandre C.

"si un lambda peut être passé comme argument de fonction alors peut-être aussi comme variable membre"

Le premier est oui, vous pouvez utiliser la déduction d'argument de modèle ou "auto" pour le faire. La seconde est probablement non, car vous devez connaître le type au point de déclaration et aucune des deux astuces précédentes ne peut être utilisée pour cela.

Celui qui peut fonctionner, mais pour lequel je ne sais pas si c'est le cas, utilise decltype.

3
dascandy