初始化在三元运算符中捕获lambda

kno*_*rs8 20 c++ lambda language-lawyer c++11 c++14

我想用以下方式创建一个lambda:

auto l1 = condition ?
          [](){ return true; } :
          [number](){ return number == 123; };
Run Code Online (Sandbox Code Playgroud)

但是,我收到了错误:

operands to ?: have different types ‘main()::<lambda()>’ and ‘main()::<lambda()>’
Run Code Online (Sandbox Code Playgroud)

显然,类型似乎是相同的.我想,number只捕获一个lambdas可能是一个问题,但我得到了同样的错误:

//check if capturing number in both lambdas would help
auto l2 = condition ?
          [number](){ return true; } :
          [number](){ return number == 123; };
//maybe the first lambda capture was optimised out? let's make sure:
auto l3 = condition ?
          [number](){ return number != 123; } :
          [number](){ return number == 123; };
Run Code Online (Sandbox Code Playgroud)

我知道我可以通过其他方式(下面)这样做,但我想知道这种行为的原因是什么.它是使用GCC6.3.1编译的,启用了C++ 14.

//compiles      
auto l4 = condition ?
          [](const int){ return true; } :
          [](const int number){ return number == 123; };
Run Code Online (Sandbox Code Playgroud)

son*_*yao 25

lambda表达式具有独特的类型(即,闭合类型,这是一个独特的无名非工会非聚合类型),即使采用相同的签名和功能体; 编译器只是不能推导出声明的变量的三元条件运算符的公共类型auto,两个闭包类型完全无关.

你可以std::function改用.例如

std::function<bool()> l1;
if (condition)
     l1 = [](){ return true; };
else
     l1 = [number](){ return number == 123; };
Run Code Online (Sandbox Code Playgroud)

因为l4,请注意,带有空捕获列表的lambda表达式可以隐式转换为相应的函数指针.在这种情况下,它们都可以转换为相同的函数指针类型(即bool(*)(int)),然后可以推导出它作为三元条件运算符的常见类型和类型l4.

  • @ knopers8因为非捕获lambdas隐式转换为它们的公共函数指针类型(例如bool(*)())... (14认同)
  • 那为什么l4会编译? (2认同)
  • @MarošBeťko带有相同签名的2个lambdas甚至2个具有相同身体的lambda具有不同的类型.它适用于Massimiliano指定的原因 (2认同)
  • @ knopers8所有人的评论都是正确的.解释也加入了答案. (2认同)

bol*_*lov 10

如果你真的想使用条件运算符,你可以这样做:

auto l1 = condition
          ? std::function<bool()>{[](){ return true; }}
          : std::function<bool()>{[number](){ return number == 123; }};
Run Code Online (Sandbox Code Playgroud)

在C++ 17中,由于类模板参数推导,这可以简化:

auto l1 = condition
          ? std::function{[](){ return true; }}
          : std::function{[number](){ return number == 123; }};
Run Code Online (Sandbox Code Playgroud)

  • @Yola是的.这是类型擦除的成本. (6认同)

Min*_*eat 5

C++ 中的 lambda 是实现函子契约的局部类的实例。我的意思是,operator() 等。这些类是不相关的并且具有不同的类型。

你的代码相当于

struct l1 {
  bool operator () const {
    return true;
  }
};

struct l2 {
  private int number_:
  l2(int number): number_(number){}

  bool operator () const {
    return number_ == 123;
  }
};

int number = ???
auto l3 = condition ? l1 : l2(number);
Run Code Online (Sandbox Code Playgroud)