C++ 关于ODR使用的另一个clang/gcc差异?
为什么这段代码用GCC(4.9和5+)编译,而不是用clang(3.5-3.9)编译C++ 关于ODR使用的另一个clang/gcc差异?,c++,c++11,g++,clang++,one-definition-rule,C++,C++11,G++,Clang++,One Definition Rule,为什么这段代码用GCC(4.9和5+)编译,而不是用clang(3.5-3.9)编译 我有一些模糊的想法,认为这种差异与ODR(一个定义规则)的使用有关,但我不太清楚这是怎么回事。x之所以使用ODR,是因为它绑定到一个引用(test的参数)。因此,必须捕获它(): 如果lambda表达式或函数调用的实例化 通用lambda odr的运算符模板使用([basic.def.odr])此 或从其到达范围自动存储持续时间的变量, 该实体应由lambda表达式捕获 违反此规则,就像标准中没有说明“无需诊断
我有一些模糊的想法,认为这种差异与ODR(一个定义规则)的使用有关,但我不太清楚这是怎么回事。
x
之所以使用ODR,是因为它绑定到一个引用(test
的参数)。因此,必须捕获它():
如果lambda表达式或函数调用的实例化
通用lambda odr的运算符模板使用([basic.def.odr])此
或从其到达范围自动存储持续时间的变量,
该实体应由lambda表达式捕获
违反此规则,就像标准中没有说明“无需诊断”或“未定义行为”的所有其他规则一样
不幸的是,GCC过早地执行常量折叠,还不能判断它是否是odr使用。这可能会导致问题。T.C.有正确的诊断,这里有一个更清晰的法律代码,其中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();
}
#包括
无效测试(常数int&a){std::cout有趣的是,如果你做了x,clang很高兴static@RichardHodges不需要捕获具有静态存储持续时间的变量。是否有人认为必须显式捕获上下文而不是编译器为我们弄清楚上下文有点愚蠢?@BitTickler不,显式捕获是一件好事。它可以防止意外地捕获循环引用(例如,捕获弱/共享ptr时)@BitTickler这是捕获默认说明符=和&@M.M的全部要点,您当然可以利用它来产生相同的效果,对吧?@M.M我非常确定[class.local]/1适用(因为lambda是本地类):本地类中的声明不应使用(3.2)封闭范围内具有自动存储持续时间的变量。@ecatmur您有相关参考吗?在N4140中,[expr.prim.lambda]部分中没有出现术语“本地类”。(尽管这是没有意义的,因为TC发现专门针对lambda有一个等效规则)@M.M@T.C.好的。我想“一个实现可能会以不同的方式定义闭包类型”是不允许扩展到它的,它在文件作用域声明闭包类型,甚至比这更糟糕;试试int main(){const int x=42;return[&]{const int&a=x;const int&b=x;return&a=&b;};}
-gcc将这两个引用绑定到不同的prvalue临时变量!@ecatmur:很抱歉发出噪音。对于注释中的代码,很难看到lambda结束和main继续的位置。是的,这很糟糕。
#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();
}