G++ 不允许在 lambda 中通过引用对 const 对象进行广义捕获?

g++ won't allow generalized capture of const object by reference in lambda?

本文关键字:对象 const lambda 不允许 引用 G++      更新时间:2023-10-16

这被g++(4.9.3和5.2.0)拒绝,但被clang 3.5.0接受:

int main() { 
    const int ci = 0;
    auto lambda = [ &cap = ci ]() { };
}

g++给出error: binding ‘const int’ to reference of type ‘int&’ discards qualifiers。看来c++不允许捕获非const引用,当然除了使用普通的c++ 11捕获[&ci]。这似乎是一个非常奇怪的约束,也许是g++中的一个bug ?

您的代码有效。§5.1.2/11是

init-capture的行为就好像它声明并显式捕获了一个形式为
" auto init-capture ; "
的变量,该变量的声明区域是lambda表达式复合语句[…]

现在,很明显,声明

auto &cap = ci;

和捕获cap是可以的。也就是说,

int main() { 
    const int ci = 0;
    auto &cap = ci;
    auto lambda = [&cap]() { };
}

使用GCC编译。除了cap的声明性区域和生命周期之外,这个代码片段和您的代码片段没有区别,因此GCC是不正确的。
这个bug已经被报告为#66735,还有一个类似的例子:

int x = 0;
auto l = [&rx = static_cast<const int&>(x)] {};

这看起来类似于gcc的错误:[c++ 14] lambda init-capture const引用失败,显示:

这段代码编译失败:

int main() {
    int x = 0;
    auto l = [&rx = static_cast<const int&>(x)]() {};
}

错误信息是:

test.cpp:3:14:错误:绑定'const int'到类型'int&'的引用丢弃限定符

auto l = [&rx = static_cast<const int&>(x)]() {

但是根据[exp .prim]。/11rx应该被捕获为auto&rx = static_cast(x),即const int&

bug报告引用了[expr.prim]。Lambda]/11表示:

init-capture的行为就好像它声明并显式捕获了一个形式为"auto init-capture;"的变量。其声明区域是lambda表达式的复合语句,但[…]