dmg
dmg

Reputation: 4481

How to declare a vector of functions (lambdas)

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

Upvotes: 8

Views: 7403

Answers (3)

W.F.
W.F.

Reputation: 13988

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]

Upvotes: 2

R Sahu
R Sahu

Reputation: 206697

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);

Upvotes: 10

SingerOfTheFall
SingerOfTheFall

Reputation: 29966

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

Upvotes: 15

Related Questions