在基于范围的循环中使用lambdas的初始化列表

时间:2014-12-21 19:35:38

标签: c++ c++11

使用gcc 4.9 -std = c ++ 14,我尝试制作一个lambdas矢量:

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

它运作得很好。然后我尝试将lambdas的初始化列表直接传递给基于范围:

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

我得到了:

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

根据错误消息的外观判断,我猜测它可能是因为&#34; lambda闭包对象&#34; s是内置语言术语,而不是直接等价的std :: function(所以没有真正的类型)。

这是什么原因?此外,这可能与实现相关,还是由规范决定的行为?

4 个答案:

答案 0 :(得分:6)

每个lambda都有自己独特的类型。所以你可能不会从不同类型的lambdas构建std :: initializer_list。

根据C ++标准(5.1.2 Lambda表达式)

  

3 lambda表达式的类型(也是的类型   closure object)是一个独特的,未命名的nonunion类类型 - 称为   闭包类型 - 其属性如下所述。

另外

  

6非泛型lambda表达式的闭包类型,没有   lambda-capture有一个公共的非虚拟非显式const转换   函数指向函数与C ++语言链接(7.5)有   与闭包类型的函数相同的参数和返回类型   呼叫运营商。

答案 1 :(得分:6)

每个lamdba都有自己的类型,因此编译器无法推断出initializer_list的类型。

你必须告诉你想要哪种类型:

  • 对于每个lambda:

    • 由于你的lambda没有捕获变量,你可以将它们衰减为指向+的函数,如下所示:

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

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

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

答案 2 :(得分:0)

每个lambda都是不相关的类型。碰巧的是,它们都可以转换为std::function<void()>,但这是因为std::function会声称转换任何内容,并且当它们可以通过void()签名并且可复制和可破坏时可以使用它

vector的情况下,有一个std::initializer_list<std::function<void()>>构造函数从构造函数列表中考虑。这是匹配,尝试和编译。

如果没有该参数(vector ctor的list参数)匹配,{}语法会在其内容中查找公共类型。没有共同的类型,所以它失败了。

该语言不会搜索每个类型和模板,以便在两个(不相关的)lambdas之间找到可能的公共类型。它不会读你的想法。

你可以这样做:

 using nullary = std::function<void()>;
 template<class T>
 using il=std::initializer_list<T>;
 for(auto f:il<nullary>{[]{ std::cout<<"hello";},[]{std::cout<<" world\n";}}){
   f();
 }

答案 3 :(得分:0)

我学习here的一个技巧是使用追溯演员。所以有了这样一个工具:

template<typename T>
struct memfun_type 
{
    using type = void;
};

template<typename Ret, typename Class, typename... Args>
struct memfun_type<Ret(Class::*)(Args...) const>
{
    using type = std::function<Ret(Args...)>;
};

template<typename F>
typename memfun_type<decltype(&F::operator())>::type
FFL(F const &func) 
{ // Function from lambda !
    return func;
}

could write这样的事情

vector<function<void()>> v = { FFL([]{cout << "foo"; }), FFL([]{cout << "bar"; }) };

for (auto&& a : v) a();