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

Posted

技术标签:

【中文标题】在 clang 和 gcc 中移动可分配的 lambda【英文标题】:move assignable lambdas in clang and gcc 【发布时间】:2016-07-23 11:38:46 【问题描述】:

我有这个程序:

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

但这与我的问题无关。

【问题讨论】:

显示你得到的错误。 【参考方案1】:

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])。 [注意: 这些特殊的成员函数像往常一样被隐式定义,因此可能被定义为删除。 -- 尾注]

然而,尽管在该问题中提出了移动赋值运算符作为一个问题,但它并没有改变答案,它继续保持开放的可能性。

【讨论】:

【参考方案2】:

具有空捕获列表的 lambda 被定义为可分配给函数指针类型,因此如果您的实际代码也具有该类型的 lambda 函数,您可以只使用函数指针。

【讨论】:

随意捕捉示例中的内容。 @user1095108 好吧,您的问题显示了一个没有捕获的 lambda,并询问 that 是否应该是可移动的。您需要为问题准备一个 MVCE(在这种情况下,它就像捕获一个变量一样简单)。

以上是关于在 clang 和 gcc 中移动可分配的 lambda的主要内容,如果未能解决你的问题,请参考以下文章

是否有类似 -mcpu= 但用于 gcc 和 clang 中的操作系统选择的东西?还是“选择最匹配的最近目标”?

如何在 OS X 中升级 gcc 的 Clang 版本?

我的 Linux 开发项目的 Clang vs GCC

gcc/clang 在基本结构的后填充中布置派生结构的字段[重复]

为啥 clang 和 gcc 在这个虚拟继承代码上存在分歧?

你如何为 clang 和 gcc 编写一个 makefile?