英特尔与海湾合作委员会在 constexpr 上

Intel vs GCC on constexpr

本文关键字:委员会 constexpr 英特尔      更新时间:2023-10-16

以下代码在 Intel-2015 中编译正常,但在 gcc 4.8.3 中失败谁是对的?

#include <iostream>
void f( int const& x ) { std::cout << x << std::endl; }
struct S
{
    static constexpr int ce = 42;
};
int main()
{
    f(S::ce);
    return 0;
}

G++ 错误:

/tmp/ccOIxa2V.o: In function `main':
test_constexpr.cpp:(.text+0x36): undefined reference to `S::ce'
collect2: error: ld returned 1 exit status

因为函数f接受引用参数,所以必须有一个引用可以在运行时指向的S::ce定义;编译器不能只用文字 42 替换参数。 因此,您必须添加一个类外定义:

const int S::ce;

就像使用非constexpr变量一样。 这会在运行时为值分配一个内存位置,供引用和其他在编译时无法计算的内容使用。

有关更多信息,请参阅此 GCC 错误报告(其中有注释解释为什么它实际上不是错误)。

我认为GCC是对的。顺便说一句,CLang 3.5.1 给出了同样的错误。

问题是,只有当常量静态变量的地址未被占用并且它们未绑定到引用时,才允许不定义常量静态变量。

您的示例将引用限定为该引用,因此需要显式定义。

从 C++11 草案 (9.4.2.3),方便编辑:

文本类型的静态数据成员可以使用 constexpr 说明符在类定义中声明;[...]如果在程序中使用 odr 使用 (3.2) 的成员,则仍应在命名空间作用域中定义该成员 [...]。

在 3.2 中:

名称显示为潜在求值表达式的变量 [...] 被 odr 使用,除非它是一个满足出现在常量表达式 (5.19) 中的要求的对象,并且立即应用左值到右值的转换 (4.1)。

粗略地说,每次使用变量时都会完成左值到右值转换的东西,除非在绑定引用或作为参数到一元获取地址运算符&时。