问题描述
下面的代码被 GCC 和 Clang 用 -std=c++14
愉快地接受,但导致 Visual Studio 2013 编译错误.
The code below is happily accepted by both GCC and Clang with -std=c++14
but causes a compile error with Visual Studio 2013.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
auto increasing = [](int lhs, int rhs){return lhs < rhs;};
auto decreasing = [](int lhs, int rhs){return lhs > rhs;};
std::vector<int> v(0, 10);
bool increase = true;
std::sort(v.begin(), v.end(), increase ? increasing : decreasing);
return 0;
}
错误是:
main.cpp(11): error C2446: ':': no conversion from 'main::<lambda_0228ee097b83254cfd8aa5f4015a245b>''main::<lambda_cb3b816d067baa9d4462132ee332363c>'main.cpp(11): 注意:没有可用的用户定义的转换运算符可以执行此转换,或者无法调用该运算符
我想我的问题是哪个编译器在这里兼容,我猜它不是 MSVC,标准中是否有部分明确处理这种情况?
I guess my question is which compiler is compliant here, I am guessing that it is not MSVC, and is there a part of the standard which explicitly deals with this situation?
推荐答案
由于 lambda 捕获它们都可以转换为具有兼容签名的函数指针,所以 gcc
和 clang
在这里是正确的.
Since neither lambda capture they can be converted to function pointers with compatible signatures, so gcc
and clang
are correct here.
有一个 gcc 错误报告很好地总结了这个主题: [c++ lambda]通过operator?:"分配 lambda expr 时出错,同时捕获 涵盖了这一点并说:
There is a gcc bug report which summarizes this topic well: [c++ lambda] error in assigning lambda expr though "operator?:" while capturing that covers this and says:
编译器的行为在我看来是正确的.的区别bar 和 foo3
中的 lambda 表达式与其他两个相比的是这些是无捕获的 lambda,因此具有转换功能函数指针.
每个 lambda 表达式对应一个唯一的类类型,所以我们foo1
和 foo2
中的 have 可以与以下进行比较类示例:
Each lambda expression corresponds to a unique class type, so what we have in foo1
and foo2
can be compared with the following class-example:
struct A{}; struct B{};
void f() { false ? A() : B(); }
这个表达式没有条件运算符的通用类型,并且是格式错误.
This expression has no common type for the conditional operator and is ill-formed.
我们在 bar
和 foo3
中的内容可以与以下内容进行比较类示例:
What we have in bar
and foo3
can be compared with the following class-example :
struct A
{
typedef void (*F)();
operator F();
};
struct B
{
typedef void (*F)();
operator F();
};
void f() { false ? A() : B(); }
这是格式良好的,因为在条件的最后一步运算符转换尝试 (5.16p5),更一般的转换是尝试并找到指向函数的公共指针.
This is well-formed, because in the last step of the conditional operator conversion attempts (5.16p5), more general conversions are attempted and these find the common pointer to function.
5.16p5
说:
否则,结果是一个纯右值.如果第二个和第三个操作数没有相同的类型,并且有(可能是 cv 限定的)类类型,重载决议用于确定转换(如果有)应用于操作数(13.3.1.2、13.6).如果重载解析失败,程序格式错误.否则,应用如此确定的转换,并且转换后的操作数用于代替原始操作数的其余部分部分.
如果我们将您的代码更改如下:
If we change your code as follows:
int x = 20 ;
auto increasing = [&x](int lhs, int rhs){return lhs < rhs;};
auto decreasing = [&x](int lhs, int rhs){return lhs > rhs;};
gcc
和 clang
都会产生错误,clang
说 (现场观看):
both gcc
and clang
generate an error, clang
says (see it live):
error: incompatible operand types ('(lambda at prog.cc:8:23)' and '(lambda at prog.cc:9:23)')
std::sort(v.begin(), v.end(), increase ? increasing : decreasing);
^ ~~~~~~~~~~ ~~~~~~~~~~
参考草案C++11标准 5.1.2
[expr.prim.lambda] 说:
没有 lambda 捕获的 lambda 表达式的闭包类型有指向指针的公共非虚拟非显式 const 转换函数具有与闭包相同的参数和返回类型的函数类型的函数调用运算符.此转换返回的值function 应该是一个函数的地址,该函数在调用时具有与调用闭包类型的函数调用运算符的效果相同.
在 C++14 标准草案中修改了措辞,但没有改变这个属性.
The wording is modified in the draft C++14 standard but does not alter this property.
更新
提交了错误报告.
这篇关于使用无捕获 lambda 表达式作为条件运算符的第二个和第三个操作数时出现 MSVC 错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!