为什么在三元运算符的分支之间返回lambda会为某些lambda工作?

时间:2017-04-01 11:47:43

标签: c++ lambda

我想根据某些条件选择一个lambda,但是对于一些lambdas,编译器说lambdas的类型在三元运算符的分支之间不匹配。

以下代码编译:

int flag = 4;
auto result = flag % 2
    ? [](int x) {
        return x + x;
    }
    : [](int x) {
        return x * x;
    };

但以下2个片段无法编译:

int flag = 4;
auto result = flag % 2
    ? [flag](int x) {
        return x + flag;
    }
    : [flag](int x) {
        return x - flag;
    };

auto result2 = flag % 2
    ? [](auto x) {
        return x + x;
    }
    : [](auto x) {
        return x * x;
    };

分别导致以下错误:

test.cpp: In function 'auto f(int)':
test.cpp:8:9: error: operands to ?: have different types 'f(int)::<lambda(int)>' and 'f(int)::<lambda(int)>'
         ? [flag](int x) {    

test.cpp: In function 'auto f(int)':
test.cpp:10:9: error: operands to ?: have different types 'f(int)::<lambda(auto:1)>' and 'f(int)::<lambda(auto:2)>'
         ? [](auto x) {
         ^

为什么最后2个片段无法编译?

2 个答案:

答案 0 :(得分:7)

第一个代码段编译因为两个lambda都可以隐式转换为int(*)(int),因此编译器可以将其用作?:表达式的类型,从而推导出result的类型。

如果捕获列表非空(情况2),则不存在对指向函数的转换(N4141中的5.1.2 / 6),因此我们最终得到两个不相关的类型,没有共同的隐式转换目标operator?:的第2和第3个操作数,因此无法再推断出三元表达式的类型。

在第3种情况下,我们有一个通用lambda,如果捕获列表为空,它有一个转换运算符,带有一个所谓的本发明模板参数列表,它定义了一组可能的转换。在我们这里的具体情况中,通用lambda可以转换为T2(*)(T1),其中T1是为参数推导出的类型,T2是lambda推导的返回类型。长话短说:没有规则选择最好的转换&#34;从那个集合开始,编译器也不能推导出我们的三元表达式的类型。

答案 1 :(得分:3)

三元表达式类型是真假分支的常见类型。运算符尝试使用复杂的规则尝试转换两个分支来查找此类型。但是两个不同的lambda具有不同的,不同的,不兼容的类型。一般来说,它们不能相互转换,所以你在第二次和第三次尝试时都会遇到错误。

但是,某些lambda(非campuring,非模板化)可以转换为函数指针。如果你有两个lambda,可以转换为相同的函数ponter类型,那么三元运算符会将该指针推导为常见类型。