[英]Are constexpr array members compile time constants?
是代码片段
struct Parameters {
static constexpr int n = 2;
static constexpr double v[n] = {4.0, 5.0};
};
合法的C ++ 11? 并且,如果是这样,是Parameters::v[0]
和Parameters::v[1]
编译时间常量或只是指针Parameters::v
本身是constexpr
(无论在编译时意味着什么)?
正如您所看到的,我通常对constexpr
数组及其在类/结构中的初始化感到困惑。 请随时回答我的具体问题,并提及有关此主题的常见陷阱等。
我发现构造没有问题。 引用C ++ 11, [dcl.constexpr]
:
constexpr
说明符应仅适用于变量的定义,函数或函数模板的声明,或文字类型的静态数据成员的声明(3.9)。 ...§9对象声明中使用的
constexpr
说明符将对象声明为const
。 这样的对象应具有文字类型并应初始化。 如果它是由构造函数调用初始化的,那么该调用应该是一个常量表达式(5.19)。 否则,或者如果在引用声明中使用constexpr说明符,则其初始值设定项中出现的每个全表达式都应为常量表达式。 用于转换初始化表达式和用于初始化的每个构造函数调用的每个隐式转换都应该是常量表达式中允许的转换之一(5.19)。
double
是文字类型,文字类型也是如此。 这意味着代码中的v[0]
和v[1]
确实是常量表达式。
struct Parameters {
static constexpr int n = 2;
static constexpr double v[n] = {4.0, 5.0};
};
int main() {
constexpr int a = Parameters::v[0];
return 0;
}
gcc 4.8.2上的这段代码编译成如下:
0000000000000000 <main>:
0: 55 push rbp
1: 48 89 e5 mov rbp,rsp
4: c7 45 fc 04 00 00 00 mov DWORD PTR [rbp-0x4],0x4
b: b8 00 00 00 00 mov eax,0x0
10: 5d pop rbp
11: c3 ret
所以是的,它是一个编译时常量。
clang 3.4产生类似的代码:
0000000000000000 <main>:
0: 55 push rbp
1: 48 89 e5 mov rbp,rsp
4: b8 00 00 00 00 mov eax,0x0
9: c7 45 fc 00 00 00 00 mov DWORD PTR [rbp-0x4],0x0
10: c7 45 f8 04 00 00 00 mov DWORD PTR [rbp-0x8],0x4
17: 5d pop rbp
18: c3 ret
同样,它是一个编译时常量。
一切都是用-O0编译的。
PS:如果a被声明为const,那么对于gcc没什么变化但是对于clang来说,值4不会直接移动,就好像是编译时常量一样。
如果a既不是const也不是constexpr,那么两个编译器都不能将Parameters :: v [0]视为编译时常量。
struct Parameters {
static constexpr int n = 2;
static constexpr double v[n] = {4.0, 5.0};
};
就我所知,这个片段本身肯定是合法的。 第7.1.5节[dcl.constexpr]的C ++ 11标准说明了这一点
constexpr说明符只能应用于......文字类型的静态数据成员的声明
并且在3.9中定义了一个文字类型 :
类型是文字类型,如果它是:
- 标量类型; 要么...
- 一个文字类型的数组
因此,就我所知, static constexpr double v[2] = { ... }
当然是有效的。
至于数组的成员是否是constexpr
...我不确定。 如果我们宣布
constexpr double d = Parameter::v[1];
那么g ++和clang都可以编译它,但是clang版本无法链接到对Parameters::v
的未定义引用。 我不知道这是否指向Clang错误,或者构造是否无效。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.