【问题标题】:Lambda capturing constexpr objectLambda 捕获 constexpr 对象
【发布时间】:2012-11-20 08:13:57
【问题描述】:

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 暗示我的解释是正确的。

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

【问题讨论】:

  • 如果你使用 clang 会发生什么?
  • @RichardJ.RossIII Clang 编译这两种情况。

标签: c++ c++11 lambda constexpr


【解决方案1】:

std::integral_constant&lt; int, i &gt; 的第二个 template-argument 用于 non-type 形式的 template-parameter,特别是 整数或枚举类型(14.3.2p1 项目符号 1),因此必须是 int 类型的转换常量表达式。

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

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

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

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

【讨论】:

  • 嗯,我在想 gcc 拒绝第二个例子可能是正确的。从 5.1.2p12 开始:An entity captured by a lambda-expression is odr-used (3.2) in the scope containing the lambda-expression. 我认为这意味着显式捕获,即[&amp;i] 意味着它是 odr-used。不过我可能是错的。
  • @JesseGood 这就是说 i 是在 enclosure 范围中使用的,而不是在复合语句中。
  • 是的,也许你是对的。我猜显式捕获不保证在 lambda 表达式中使用 odr。尽管该区域可能会更清晰。
【解决方案2】:

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

【讨论】:

  • 草稿定期发布;他们有效地修复了标准中的勘误表,因为委员会仍在“修复错误”而不是“添加功能”。最新的是 N3485。问题的重点是询问是否保证不引入诸如j之类的声明。
  • @Potatoswatter 感谢您提供此信息。然后我必须“更新”我的 N3242 草案。
猜你喜欢
  • 2019-08-03
  • 1970-01-01
  • 2013-12-15
  • 2015-04-30
  • 2017-07-25
  • 2021-03-21
  • 2017-03-24
  • 1970-01-01
相关资源
最近更新 更多