Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using an initializer list of lambdas in a range-based loop

Tags:

c++

c++11

With gcc 4.9 -std=c++14, I tried making a vector of lambdas:

vector<function<void ()>> v = {[]{cout << "foo";}, []{cout << "bar";}};
for (auto&& a: v) a();

And it worked pretty well. Then I tried passing the initializer list of lambdas to the range-based for directly:

for (auto&& a: {[]{cout << "foo";}, []{cout << "bar";}}) a();

And I got:

error: unable to deduce 'std::initializer_list<auto>&&' from '{<lambda closure object>main()::<lambda()>{}, <lambda closure object>main()::<lambda()>{}}'

Judging by the appearance of the error message, I made a wild guess that it is probably because "lambda closure object"s are built-in language terms, and not direct equivalents of std::function (so no real types).

What is the deeper cause of this? Also, could this be implementation-related, or is such behavior dictated by the specification?

like image 249
Thanasis Papoutsidakis Avatar asked Dec 21 '14 19:12

Thanasis Papoutsidakis


2 Answers

Each lambda has its own unique type. So you may not build std::initializer_list from lambdas of different types.

According to the C++ Standard (5.1.2 Lambda expressions)

3 The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed nonunion class type — called the closure type — whose properties are described below.

Also

6 The closure type for a non-generic lambda-expression with no lambda-capture has a public non-virtual nonexplicit const conversion function to pointer to function with C++ language linkage (7.5) having the same parameter and return types as the closure type’s function call operator.

like image 53
Vlad from Moscow Avatar answered Sep 27 '22 21:09

Vlad from Moscow


Each lamdba has its own type, so compiler cannot deduced the type of the initializer_list.

You have to tell which type you want:

  • For each lambda:

    • As your lambda doesn't capture variables, you may decay them to pointer to function with + as follow:

      for (auto&& a: {+[]{std::cout << "foo";}, +[]{std::cout << "bar";}}) a();
      
    • using function<void()>:

      for (auto&& a: {std::function<void()>([]{std::cout << "foo";}),
                      std::function<void()>([]{std::cout << "bar";})}) a();
      
  • For the initializer_list:

    for (auto&& a: std::initializer_list<std::function<void()>>{
                       []{std::cout << "foo";}, 
                       []{std::cout << "bar";}}) a();
    
like image 38
Jarod42 Avatar answered Sep 27 '22 22:09

Jarod42