【问题标题】:Implicitly capture const variable in a template lambda with no capture-default specified在未指定捕获默认值的模板 lambda 中隐式捕获 const 变量
【发布时间】:2021-06-02 00:44:39
【问题描述】:

考虑以下代码:

auto f() {
  const auto x = 1;
  return [] (auto) { return x; };
}

GCC and MSVC compiles fine but Clang rejected it。我应该信任哪个编译器?这是 Clang 尚未实现的编译器扩展还是只是 Clang 错误?

【问题讨论】:

  • 如果变量具有 const 非易失性整数或枚举类型并且已使用常量表达式初始化,则 lambda 表达式可以读取变量的值而不捕获它 @987654322 @
  • 仅供参考 - 小的变化,它编译 return [] (auto y) { return x + y; }; 也许添加 [language-lawyer]
  • 另一件事,为什么gcc 会抛出警告(variable 'x' set but not used [-Wunused-but-set-variable]),即使它在 lambda 中使用?
  • 可能相关:#20289
  • 更陌生的clang编译return [] (auto) { return +x; };

标签: c++ lambda c++17 language-lawyer c++20


【解决方案1】:

这是一个clang错误。

我们的规则是[basic.def.odr]/9:

如果满足以下条件,则本地实体可在范围内使用 odr:

  • 本地实体不是 *this,或者存在封闭类或非 lambda 函数参数范围,如果最里面的此类范围是函数参数范围,则它对应于非静态成员函数,并且李>
  • 对于在引入实体的点和范围之间的每个中间范围 ([basic.scope.scope])(其中 *this 被认为是在最内层的封闭类或非 lambda 函数定义范围内引入) , 任何一个:
    • 中间作用域是块作用域,或者
    • 干预范围是具有命名实体的简单捕获或具有默认捕获的 lambda 表达式的函数参数范围,并且 lambda 表达式的块范围也是一个干预范围。

如果一个本地实体在其不可使用的范围内被使用,则程序是非良构的。

在我们的示例中:

auto f() {
  const auto x = 1;
  return [] (auto) { return x; };
}

x 在 lambda 主体中不可使用,因为中间范围不捕获 x(既不是简单捕获也不是默认捕获)。

所以,它不是 odr 可用的。但它是 odr 使用的吗?不,来自[basic.def.odr]/4

如果表达式是表示它的 id 表达式,则变量由表达式命名。变量x 的名称显示为潜在评估表达式EE odr 使用,除非

  • x 是可用于常量表达式 ([expr.const]) 的引用,或者
  • x 是非引用类型的变量,可用于常量表达式并且没有可变子对象,E 是非易失性限定的非类类型表达式的潜在结果集合中的一个元素应用了左值到右值的转换 ([conv.lval]),或者
  • x 是非引用类型的变量,E 是未应用左值到右值转换的废弃值表达式 ([expr.prop]) 的潜在结果集的元素.

第二个项目符号适用(并且方便地我们的变量甚至命名为x!)x 可用于常量表达式,因为它是常量整数类型,E 在这里是左值到右值的转换。

所以x不是odr-usable,也不是odr-used,所以这里没有问题。


事实上,我们甚至在[expr.prim.lambda.capture]/7 中有这个例子:

void f(int, const int (&)[2] = {});         // #1
void f(const int&, const int (&)[1]);       // #2
void test() {
  const int x = 17;
  auto g = [](auto a) {
    f(x);                       // OK: calls #1, does not capture x
  };
}

【讨论】:

    【解决方案2】:

    是的,Clang 错误。

    适用规则来自[basic.def.odr]/9

    如果一个本地实体在其不可使用的范围内被使用,则程序是非良构的。

    值得注意的是,规则说“如果您使用 odr-use,它的格式不正确”,而不是“如果我们无法确定它是否是 odr-use,它的格式不正确”。

    在该函数调用运算符模板的任何特化中都没有使用 x

    【讨论】:

      猜你喜欢
      • 2015-10-28
      • 2015-07-24
      • 1970-01-01
      • 1970-01-01
      • 2018-12-26
      • 1970-01-01
      • 2011-05-17
      • 2021-04-07
      • 1970-01-01
      相关资源
      最近更新 更多