103

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?

2

6 Answers 6

151

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; }); 
Sign up to request clarification or add additional context in comments.

6 Comments

Managing a hundred-man developer team sounds more like a nightmare to me :)
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.
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.
Is it possible to create a vector storing functions of different type? i.e. instead of limiting it to std::function<int(), could I use different function prototypes?
@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?
|
42

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.

2 Comments

Don't need () for lambdas that take no arguments.
I'm getting a Solution not found — Is the Link ideone.com/2C2aQ dead meanwhile?
19

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 

6 Comments

For the record auto ignore = *[] { return 10; }; would make ignore an int(*)().
@Luc, oh that is gross! When did they add that?
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.)
Ah... Dereferencing the resulting pointer. That makes sense. Was the missing () intentional or accidental?
Intentional, the lambda expression is equivalent (but two characters shorter).
|
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!

2 Comments

Which could actually be useful if the pushback happens in a loop with different parameters. Presumably for lazy evaluation purposes.
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
10

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.

3 Comments

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)).
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.
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!!
4

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.