web-dev-qa-db-fra.com

Pourquoi ne puis-je pas créer un vecteur de lambdas (du même type) en C ++ 11?

J'essayais de créer un vecteur de lambda, mais j'ai échoué:

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

Jusqu'à la ligne # 2, il compile très bien . Mais la ligne # 3 donne erreur de compilation :

erreur: pas de fonction correspondante pour l'appel à 'std :: vector <main () :: <lambda () >> :: Push_back (main () :: <lambda ()>)'

Je ne veux pas d'un vecteur de pointeurs de fonction ou d'un vecteur d'objets de fonction. Cependant, le vecteur d'objets fonctionnels qui encapsulent des expressions lambda réelles , fonctionnerait pour moi. Est-ce possible?

83
Nawaz

Chaque lambda a n type différent - même s'ils ont la même signature. Vous devez utiliser un conteneur d'encapsulation au moment de l'exécution tel que std::function si vous voulez faire quelque chose comme ça.

par exemple.:

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

Toutes les expressions lambda ont un type différent, même si elles sont identiques caractère par caractère . Vous poussez une lambda d'un type différent (car c'est une autre expression) dans le vecteur, et cela ne fonctionnera évidemment pas.

ne solution consiste à faire un vecteur de std::function<int()> à la place.

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

Sur une autre note, ce n'est pas une bonne idée d'utiliser [&] lorsque vous ne capturez rien.

39

Bien que ce que d'autres ont dit soit pertinent, il est toujours possible de déclarer et d'utiliser un vecteur de lambda, bien qu'il ne soit pas très utile:

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

Ainsi, vous pouvez y stocker n'importe quel nombre de lambdas, tant qu'il s'agit d'une copie/d'un déplacement de lambda!

17
Luc Danton

Si votre lambda est sans état, c'est-à-dire [](...){...}, C++ 11 lui permet de se dégrader en un pointeur de fonction. En théorie, un compilateur compatible C++ 11 serait capable de compiler ceci:

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

Vous pouvez utiliser une fonction de génération lambda (mise à jour avec le correctif suggéré par Nawaz):

#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++;
    }
}

Mais je pense que vous avez essentiellement fait votre propre classe à ce stade. Sinon, si les lambdas ont des caputres/args complètement différents, etc., vous devrez probablement utiliser un Tuple.

4
antediluvian

Chaque lambda est d'un type différent. Tu dois utiliser std::Tuple au lieu de std::vector.

3
Paul Fultz II