23

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,后一个示例对我来说似乎是正确的:

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

似乎ilambda 内捕获的对象是指封闭范围内的变量constexpr,而不仅仅是一个const引用。

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

有什么明确说明引用捕获是指封闭范围内的对象还是引用?

4

2 回答 2

12

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

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

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

不是 odr-use的id-expression是指原始实体,而不是闭包类型的成员。

尽管整个段落都在讨论按副本捕获,但没有理由不将此规则也应用于按引用捕获。标准对此不明确也就不足为奇了。确实没有理由通过引用捕获可以在转换后的常量表达式中使用的实体。

于 2012-11-20T10:52:34.627 回答
0

首先,我可以在 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它不是“整数常量”。

于 2012-11-20T10:39:04.897 回答