我有这个程序:
int main()
{
auto l([](){});
::std::cout << ::std::is_move_assignable<decltype(l)>{} << ::std::endl;
}
gcc-6.1.1显示0
clang-3.8.0显示1
这导致程序中出现编译错误。哪个编译器是对的?
错误:
error: object of type '(lambda at t.cpp:5:5)' cannot be assigned because its copy assignment operator is implicitly deleted
但这与我的问题无关。
答案 0 :(得分:4)
N4140(大致是C ++ 14)说:
5.1.2 Lambda表达式[expr.prim.lambda]
20与 lambda-expression 关联的闭包类型具有已删除(8.4.3)的默认构造函数和已删除的复制赋值运算符。它有一个隐式声明的复制构造函数(12.8),并且可能有一个隐式声明的移动构造函数(12.8)。 [注意:复制/移动构造函数的隐式定义方式与隐式定义任何其他隐式声明的复制/移动构造函数的方式相同。 - 结束记录]
请注意,这并未提及是否隐式声明了已删除的复制赋值运算符。编译器将lambda转换为类定义和实例化,但是可以通过隐式声明复制赋值运算符的方式巧妙地定义该类,但该类的某些其他属性会导致隐式复制赋值运算符被删除。
然后:
12.8复制和移动类对象[class.copy]
20如果类
时,才会隐式声明一个默认值。X
的定义没有明确声明一个移动赋值运算符,当且仅当(20.1) -
X
没有用户声明的复制构造函数,(20.2) -
X
没有用户声明的移动构造函数,(20.3) -
X
没有用户声明的复制赋值运算符,(20.4) -
X
没有用户声明的析构函数。
如果隐式声明lambda的复制赋值运算符,则它不会禁止生成移动赋值运算符。如果显式声明,则移动赋值运算符将被抑制。
根据标准的字面措辞,这两种行为都是可以防御的。
CWG issue 1891部分解决了这个问题,将文本更改为:
与 lambda-expression 关联的闭包类型没有默认构造函数和已删除的复制赋值运算符。它有一个默认的复制构造函数和一个默认的移动构造函数(12.8 [class.copy])。 [注意:这些特殊成员函数通常是隐式定义的,因此可能被定义为已删除。 - 结束记录]
然而,尽管移动分配操作员在该问题中被提出作为一个问题,但它并没有改变答案,它继续留下可能性。
答案 1 :(得分:-1)
具有空捕获列表的lambda 被定义为可分配给函数指针类型,因此如果您的实际代码也具有该类型的lambda函数,则可以使用函数指针。 / p>