const&& 绑定到 lambda 捕获中的 ref:clang 与 gcc?

Kon*_*rov 6 c++ language-lawyer c++20

在下面的代码中:

int foo() {
  int a = 5;
  auto l = [&r = std::move(std::as_const(a))] { return r; };
  return l();  
}
Run Code Online (Sandbox Code Playgroud)

clang 编译得很好

gcc 产生错误。

error: cannot capture 'std::move<const int&>((* & std::as_const<int>(a)))' by reference
Run Code Online (Sandbox Code Playgroud)

我需要社区的帮助来从 C++ 标准的角度争论这个案例:谁在 C++20 中是正确的以及为什么到底。

从 [expr.prim.lambda.capture] 我不清楚这个子句是否:

不带省略号的 init-capture 的行为就像它声明并显式捕获“auto init-capture”形式的变量一样

意味着 clang 是对的?如果是,那么为什么删除 as_const 会使这两者都出错?

godbolt 上的代码示例

use*_*522 3

似乎是 GCC 的错误。init-capture 的行为应该就像声明带有auto前缀的相应变量一样,然后捕获该变量(与标准中的引用完全相同):

auto &r = std::move(std::as_const(a));
Run Code Online (Sandbox Code Playgroud)

这将推断auto变量const int具有类型const int&并且初始化将是格式良好的,因为初始值设定项是左值引用可以直接绑定到的类型的右const intconst

但是std::move这里没有任何效果,如果没有它,结果将是相同的。(std::moveconst 类型上基本上没有意义。)


它会失败,as_const因为 thenauto将被推导为恰好int使变量具有 type int&。然后,您尝试从右值( 的结果std::move)初始化它,这在初始化非左值引用时是不允许的const