8

I have seen how to declare a vector of functions (see calling a function from a vector).

But that answer users pointers. How can I create a vector of functions/lambdas using the new syntax in modern C++?

the examples of functions using the new syntax typically use auto:

auto f = [] (std::string msg) -> void { 
    std::cout << msg << std::endl;
};

What is the actual type of f? so I can declare a vector of this type?

thank you very much for any help

Community
  • 1
  • 1
dmg
  • 4,231
  • 1
  • 18
  • 24
  • 2
    "*What is the actual type of f?*" Unnameable. "*so I can declare a vector of this type?*" Yes, but it wouldn't help, because lambdas are not default-constructible. `std::vector>` will probably suit your purposes. – ildjarn Nov 22 '16 at 07:46
  • 2
    you can actually still use pointers if the lambda has no closures, btw – kmdreko Nov 22 '16 at 07:47
  • 1
    If you don't need a vector (i.e. if the actual lambdas are known at compile time) you could create a std::tuple of lambdas. – dats Nov 22 '16 at 09:18
  • I did something similar, in a library: https://github.com/shirayukikitsune/SceneGraph/blob/master/SceneGraph/Base/Callback.h – Bruno Ferreira Nov 22 '16 at 19:59

3 Answers3

15

Use std::function with the corresponding type:

std::vector<std::function<void(void)>> vec;
vec.push_back([]()->void{});

In your case it would be std::function<void(std::string)>.

The exact type of a lambda is meaningless per standard ([expr.prim.lambda]/3):

The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type

SingerOfTheFall
  • 29,228
  • 8
  • 68
  • 105
9

What is the actual type of f? so I can declare a vector of this type?

Type of f can only be deduced by using auto. You can declare a vector of this type using

std::vector<decltype(f)> v;

However, it is not very useful. Lambda functions that look strikingly similar have different types. To make matters worse, lambda functions that have identical body also have different types.

auto f = [] (std::string msg) -> void { 
    std::cout << msg << std::endl;
};

auto g = [] (std::string msg) -> void { 
    std::cout << msg << std::endl;
};

auto h = [] (std::string msg) -> void { 
    std::cout << msg << '+' << msg << std::endl;
};

Given the above functions, you can't use

std::vector<decltype(f)> v;
v.push_back(f);  // OK
v.push_back(g);  // Not OK
v.push_back(h);  // Not OK

Your best option is to create a std::vector of std::functions. You can add the lambda functions to that std::vector. Given the above definitions of f and g, you can use:

std::vector<std::function<void(std::string)>> v;
v.push_back(f);
v.push_back(g);
v.push_back(h);
R Sahu
  • 204,454
  • 14
  • 159
  • 270
2

As mentioned each lambda you declare has unique context specific type even if it has seemingly identical signature. This is why vector of lambdas has only theoretical value - you would be able to push there at most one lambda... You have two choices - you could go along with proposed approach from other answers and store lambdas into a type-erasure std::function before putting them into vector or put your lambdas into a "container" that would collect the type of each element apart from the lambda object itself - std::tuple:

auto t = std::make_tuple([](){ std::cout<<"First lambda" << std::endl; },
                         [](){ std::cout<<"Second lambda"<< std::endl; },
                         [](){ std::cout<<"Third lambda" << std::endl; });

and get appropriate lambda at compile-time:

std::get<0>(t)(); // the value in get must be known at compile time! 
                  // otherwise compiler won't be able to establish type 
                  // of lambda and the whole point of using tuple is lost

[live demo]

W.F.
  • 13,888
  • 2
  • 34
  • 81