2017-04-01 45 views
4

我想选择取决于一些有条件的拉姆达,但是编译器,对于一些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个片段不能编译?

+5

说“错误”时请附上确切消息。 –

+0

顺便说一句,作为一种解决方法,你可以明确地将至少一个lambda转换为'std :: function '。 –

+0

我该如何解决lambda具有'auto'参数的最后一个问题? –

回答

7

第一个代码段编译,因为两者的lambda是隐式转换为int(*)(int),所以编译器可使用作为?:表达式的类型,从而推断出的result类型。

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

如果3,我们有一个通用的λ,其中,如果捕获列表是空的,具有转换运营商,所谓的发明模板参数列表定义了一组可能的转换。在我们这里的具体情况,一般的lambda表达式可以转换为T2(*)(T1),其中T1是推导出参数的类型和T2是拉姆达的推断返回类型。长话短说:没有规则可以从该集合中选择“最佳转换”,因此编译器无法为我们的三元表达式推导出一种类型。

+1

好吧,无捕获的泛型lambdas确实具有转换为函数指针的功能;问题在于它们可以很好地转换为与它们的签名匹配的每种函数指针,所以你会得到一个含糊不清的结果。 –

+0

@ T.C。修正了,谢谢你的发现。 –

3

三元表达式类型是真假两分支中的常见类型。运算符试图通过使用复杂的规则来尝试转换两个分支来查找此类型。但是两种不同的lambda具有不同的,不同的,不兼容的类型。一般来说,他们不能相互转换,所以你有第二次和第三次尝试的呃。

然而,某些种类的lambda(非campuring,非模板化)可以被转换为一个函数指针。如果有两个lambda表达式,可转换为相同的函数ponter类型,则三元运算符将推断该指针为常见类型。