在clang和gcc中移动可分配的lambdas

时间:2016-07-23 11:38:47

标签: c++ gcc lambda clang c++17

我有这个程序:

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

但这与我的问题无关。

2 个答案:

答案 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>