Lambda正在捕获constexpr对象

Lambda capturing constexpr object

本文关键字:constexpr 对象 Lambda      更新时间:2023-10-16

GCC 4.7.2编译如下:

constexpr int i = 5;
[]{ std::integral_constant< int, i >(); }; // nonstandard: i not captured

但不是这个:

constexpr int i = 5;
[&i]{ std::integral_constant< int, i >(); }; // GCC says i not constexpr

根据C++11§5.1.2/15:,后一个例子对我来说似乎是正确的

如果实体是隐式或显式捕获的,但不是通过复制捕获的,则通过引用捕获实体。未指定是否在通过引用捕获的实体的闭包类型中声明其他未命名的非静态数据成员。

lambda中捕获的对象i似乎引用了封闭范围中的变量constexpr,而不仅仅是const引用。

该标准明确表示,按值捕获的使用转换为lambda对象的相应成员的使用。我认为5.1.2暗示了我的解释是正确的。

有没有明确说明引用捕获是指封闭范围中的对象还是引用?

std::integral_constant< int, i >的第二个模板参数用于非类型形式的模版参数,特别是积分或枚举类型(14.3.2p1项目符号1),因此必须是int类型的转换常量表达式。

lambda表达式中,当在复合语句(5.1.2p11)中使用实体odr时,会发生隐式捕获;在显式模板实例化中使用转换后的常量表达式不是odr使用(3.2p3),因此第一个示例是有效的。

在第二个例子中,我认为gcc拒绝它是不正确的;5.1.2p17在注释中表示:

不是odr使用的id表达式引用原始实体,而不是闭包类型的成员。

尽管整个段落都在讨论通过复制捕获,但没有理由不将此规则应用于通过引用捕获。毫不奇怪,标准对此并不明确;实际上没有理由捕获一个可以通过引用在转换的常量表达式中使用的实体。

首先,我可以用Ubuntu 12.04上的gcc 4.6.3和clang 3.0来确认您的观察结果。

我没有C++11标准(只有草案),所以我不能对此发表评论。但根据我的理解,看看的等效声明

constexpr int i = 5;
const int &j = i;
std::integral_constant<int, j>();

gcc和clang都没有编译它,因为j不是"积分常数"。