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(其中有解释为什么它实际上不是错误的注释)。
以下代码在 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(其中有解释为什么它实际上不是错误的注释)。