Intel vs GCC on constexpr

Intel vs GCC on constexpr

以下代码在 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

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

问题是,只有在不获取地址且未绑定到引用的情况下,才允许不定义常量静态变量。

您的示例绑定了对它的引用,因此需要显式定义。

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

A static data member of literal type can be declared in the class definition with the constexpr specifier; [...] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program [...].

在 3.2 中:

A variable [...] whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied.

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

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

const int S::ce;

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

有关详细信息,请参阅 this GCC bug report(其中有解释为什么它实际上不是错误的注释)。