98

I was trying to create a vector of lambda, but failed:

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

Up to line #2, it compiles fine. But the line#3 gives compilation error:

error: no matching function for call to 'std::vector<main()::<lambda()>>::push_back(main()::<lambda()>)'

I don't want a vector of function pointers or vector of function objects. However, vector of function objects which encapsulate real lambda expressions, would work for me. Is this possible?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 24
    "I don't want a vector of function pointers or vector of function objects." But that's what you asked for. A lambda **is** a function object. – Nicol Bolas Sep 19 '11 at 22:47
  • Closely Related: [What is the type of lambda when deduced with “auto” in C++11?](http://stackoverflow.com/q/7951377/514235). – iammilind Dec 21 '16 at 08:33

6 Answers6

147

Every lambda has a different type—even if they have the same signature. You must use a run-time encapsulating container such as std::function if you want to do something like that.

e.g.:

std::vector<std::function<int()>> functors;
functors.push_back([&] { return 100; });
functors.push_back([&] { return  10; });
ajeh
  • 2,652
  • 2
  • 34
  • 65
Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 53
    Managing a hundred-man developer team sounds more like a nightmare to me :) – Jeremy Friesner Sep 19 '11 at 21:38
  • 11
    Also, don't forget that captureless lambdas ([]-style) can degrade into function pointers. So he could store an array of function pointers of the same type. Note that VC10 doesn't implement that yet. – Nicol Bolas Sep 19 '11 at 22:48
  • By the way, shouldn't capture-less be used in those examples anyway? Or is it necessary? - By the way, captureless lambda to function pointer seems to be supported in VC11. Didn't test it though. – Klaim Sep 20 '11 at 09:06
  • I generally find that I prefer to always capture everything by reference, unless I have something specific in mind. It just makes it easier to go back and change them, since it's the behaviour I expect. – Puppy Sep 20 '11 at 10:09
  • 2
    Is it possible to create a vector storing functions of different type? i.e. instead of limiting it to `std::function – manatttta Jan 21 '15 at 09:48
  • 2
    @manatttta What would be the point? Containers exist to store objects of the same type, to organise and manipulate them together. You might as well ask 'can I create a `vector` storing both `std::function` and `std::string`?' And the answer is the same: No, because that's not the intended use. You could use a 'variant'-style class to perform enough type erasure to put disparate things in a container, while including a method for a user to determine the 'real' type and hence choose what to do with (e.g. how to call) each element... but again, why go to such lengths? Is there any real rationale? – underscore_d Jul 02 '16 at 22:51
41

All lambda expressions have a different type, even if they are identical character-by-character. You're pushing a lambda of a different type (because it's another expression) into the vector, and that obviously won't work.

One solution is to make a vector of std::function<int()> instead.

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

On another note, it's not a good idea to use [&] when you're not capturing anything.

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
19

While what others have said is relevant, it is still possible to declare and use a vector of lambda, although it's not very useful:

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

So, you can store any number of lambdas in there, so long as it's a copy/move of lambda!

squ1dd13
  • 84
  • 2
  • 9
Luc Danton
  • 34,649
  • 6
  • 70
  • 114
  • Which could actually be useful if the pushback happens in a loop with different parameters. Presumably for lazy evaluation purposes. – MaHuJa Dec 26 '11 at 22:49
  • 7
    No you don't put the parameters in the vector, just the function object.. So it would be a vector with all copies of the same lambda – hariseldon78 Oct 17 '12 at 16:12
17

If your lambda is stateless, i.e., [](...){...}, C++11 allows it to degrade into a function pointer. In theory, a C++11 compliant compiler would be able to compile this:

auto ignore = []() { return 10; };  //1 note misssing & in []!
std::vector<int (*)()> v;     //2
v.push_back([]() { return 100; });  //3
MSN
  • 53,214
  • 7
  • 75
  • 105
  • 4
    For the record `auto ignore = *[] { return 10; };` would make `ignore` an `int(*)()`. – Luc Danton Sep 19 '11 at 22:19
  • 1
    @Luc, oh that is gross! When did they add that? – MSN Sep 19 '11 at 22:35
  • 3
    Well, since the conversion function that allows to take a function pointer in the first place is mandated to not be `explicit`, dereferencing a lambda expression is valid and dereferences the pointer resulting from the conversion. Then using `auto` decays that reference back into a pointer. (Using `auto&` or `auto&&` would have kept the reference.) – Luc Danton Sep 19 '11 at 22:41
  • Ah... Dereferencing the resulting pointer. That makes sense. Was the missing `()` intentional or accidental? – MSN Sep 20 '11 at 00:03
  • Intentional, the lambda expression is equivalent (but two characters shorter). – Luc Danton Sep 20 '11 at 00:12
  • It works. I tested with std::vector which has same performance as std::function. So seem no reason to make life more difficult. – iaomw Sep 27 '22 at 16:11
9

You could use a lambda generating function (updated with fix suggested by 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++;
    }
}

But I think you basically made your own class at this point. Otherwise if the lambdas have completely different caputres/args etc. you probably have to use a tuple.

antediluvian
  • 91
  • 1
  • 2
  • Nice idea to wrap it in a function like `lambda_gen` which can be in turn a lambda itself. However, `auto a = lambda_gen(1);` makes an unnecessary call, which can be avoided if we write this [`decltype(lambda_gen(1))`](http://coliru.stacked-crooked.com/a/27c315671c196a56). – Nawaz Jul 28 '16 at 10:31
  • Doesn't that still make an extra call though? Also another minor point is that the question states C++11 so one would need to add a trailing return type to the function I think. – antediluvian Jul 28 '16 at 12:09
  • No. Anything inside `decltype` is *unevaluated*, so the call is not actually made. It is the same case with `sizeof` as well. Also, this code wont work in C++11 even if you add trailing return type!! – Nawaz Jul 28 '16 at 15:12
4

Each lambda is a different type. You must use std::tuple instead of std::vector.

Paul Fultz II
  • 17,682
  • 13
  • 62
  • 59