C++ constexpr上的英特尔vs GCC

C++ constexpr上的英特尔vs GCC,c++,gcc,intel,static-members,constexpr,C++,Gcc,Intel,Static Members,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; } 我认为GCC是对的。顺便说

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

我认为GCC是对的。顺便说一句,Clang3.5.1给出了相同的错误

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

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

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

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

第3.2节:

除非变量[…]是满足常量表达式(5.19)中出现要求的对象,并且立即应用左值到右值的转换(4.1),否则将使用odr变量[…]


粗略地说,左值到右值的转换是在每次使用变量时完成的,除非将引用或作为参数绑定到一元take address运算符
&

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

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


有关更多信息,请参阅(其中有解释为什么它实际上不是一个bug的注释)。

GCC是对的。使用
s.se
是正确的,但是
std::cout
ce
是静态的,
s::ce
是正确的。它与
constexpr
@ForceBru有关,点运算符作用于对象,而不是类型。@user2052436,为什么u使用GCC而不是g++?那是C++,不是吗?都是对的。这是一个不需要诊断的ODR冲突正如您所建议的,icc工作,而g++失败,出现
错误:重新声明的S::ce'
。如果我添加
constexpr int test::ce,然后两者都能工作。哎呀,很抱歉
测试::
这件事-我从测试程序中复制了代码,但实际上没有对照您的问题进行检查。但是
constints::ce为我工作;您不应该在类外定义中需要
constexpr
。如果
S::ce
声明为
const
,则对我有效。但如果声明为
constexpr
,则类外定义也必须是
constexpr
。否则,icc和g++都会失败。也就是说,定义和声明必须完全匹配,不能在一个位置有
const
,在另一个位置有
constepr
。编译器版本是否不同?我们是否可以大胆地说,
static
类内声明前面有一个隐式的
extern
const int S::ce;