我想根据某些条件选择一个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个片段无法编译?
答案 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类型,那么三元运算符会将该指针推导为常见类型。