13

为什么这段代码可以用 GCC(4.9 和 5+)编译,但不能用 clang(3.5-3.9)编译?

void test(const int&) { }
int main() {
  const int x = 42;
  auto f = []{ test(x); };
}

我有一些模糊的想法,即差异与 ODR(一个定义规则)的使用有关,但我不太了解,无法弄清楚这里发生了什么。

4

2 回答 2

16

x是 odr-used 因为它绑定到一个引用(test的参数)。因此必须捕获它([expr.prim.lambda]/13):

如果lambda 表达式或通用 lambda odr-uses ([basic.def.odr]) 的函数调用运算符模板的实例化this 或具有从其到达范围内自动存储持续时间的变量,则该实体应由lambda捕获-表达式

违反此规则,就像标准中没有说“不需要诊断”或“未定义行为”的所有其他规则一样,需要诊断

不幸的是,GCC 在判断它是否是 odr-use 之前过早地执行常量折叠。这可能会导致诸如[&]()->const int & { return x; }返回悬空引用等问题。

于 2016-03-17T21:27:10.410 回答
8

TC 有正确的诊断,这里有一个更清晰的法律代码,其中 clang 做了正确的事情而 gcc 没有:

#include <iostream>

void test(const int&a) { std::cout << "in test() -- " << &a << "\n"; }
int main() {
  const int x = 42;
  std::cout << "in main() -- " << &x << "\n";
  auto f = [&]{ test(x); };
  f();
}

gcc 为引用捕获变量打印与原始地址不同的地址!

于 2016-03-17T21:40:52.973 回答