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

Posted

技术标签:

【中文标题】g++ 不允许在 lambda 中通过引用对 const 对象进行广义捕获?【英文标题】:g++ won't allow generalized capture of const object by reference in lambda? 【发布时间】:2015-11-02 08:23:54 【问题描述】:

这被 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。似乎 g++ 拒绝允许捕获非常量引用,当然除了使用普通的旧 C++11 捕获 [&ci]。这似乎是一个非常奇怪的约束,也许是 g++ 中的一个错误?

【问题讨论】:

***.com/questions/3772867/… @CoryKramer,这个问题确实密切相关。我今天也评论了这个问题。我想我的问题是:“给定一个 const 对象,我如何通过引用来捕获它?”。而这个问题是“给定一个 non-const 对象,我如何通过 const 引用捕获它?”。我想一个好的答案会涵盖这两个问题。 【参考方案1】:

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

init-capture 的行为就好像它声明并显式捕获了形式为 “auto init-capture ; 的变量”,其声明区域是 lambda-expressioncompound-statement […]

现在,明确地声明

auto &cap = ci;

捕获cap 很好。也就是说,

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

compiles with GCC。除了cap的声明区域和生命周期之外,这个sn-p和你的没有区别,因此GCC是不正确的。 这个错误已经被报告为#66735,还有一个类似的例子:

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

【讨论】:

这样的话,我会尽快报告的。我非常惊讶以前没有注意到这个错误 - 它似乎是一个如此简单的例子。我肯定不是第一个尝试通过引用捕获 const 对象的人吗? @AaronMcDaid 你不是,但使用初始化捕获通过引用捕获const 对象可能很少发生。 This report 非常相似。我可能会用我稍微简单的例子来评论那个错误。 @AaronMcDaid 谢谢。我会将其纳入答案中。 我在尝试通过 const 捕获非 const 对象时发现了这一点,首先将其 const 转换为 const。但是,是的,捕获一个已经是 const 的对象(即我的问题)会很奇怪!【参考方案2】:

这看起来类似于gcc bug: [C++14] lambda init-capture fails for const references,它说:

这段代码编译失败:

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)]() 

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

错误报告引用 [expr.prim.lambda]/11 说:

init-capture 的行为就好像它声明并显式捕获了“auto init-capture ;”形式的变量 其声明区域是 lambda 表达式的复合语句,除了 [...]

【讨论】:

以上是关于g++ 不允许在 lambda 中通过引用对 const 对象进行广义捕获?的主要内容,如果未能解决你的问题,请参考以下文章

无法在pandas中通过lambda填充多列中的NaN值

如何在没有 lambda 函数的 React Native 中通过单个处理程序处理几个 TextInput?

在CDK中通过ARN将事件源添加到Lambda

Python中通过lambda抛异常的奇迹淫巧

在python中通过引用传递引用

OSGI框架中通过BundleContext对象对服务的注册与引用