代码片段是
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
数组及其在类/结构中的初始化感到困惑。请随时回答我的具体问题,并提及有关此主题的常见陷阱等。
答案 0 :(得分:4)
我发现构造没有问题。引用C ++ 11,[dcl.constexpr]
:
§1
constexpr
说明符应仅适用于变量的定义,函数的声明或 函数模板,或文字类型的静态数据成员的声明(3.9)。 ...§9对象声明中使用的
constexpr
说明符将对象声明为const
。这样的对象应该有 字面类型,应初始化。如果它是由构造函数调用初始化的,那么该调用应该是一个常量 表达式(5.19)。否则,或者如果在引用声明中使用constexpr说明符,则每个完整表达式 出现在其初始化程序中的应该是一个常量表达式。每个隐式转换用于 转换初始化表达式和用于初始化的每个构造函数调用应该是其中之一 允许使用常量表达式(5.19)。
double
是文字类型,文字类型也是如此。这意味着代码中的v[0]
和v[1]
确实是常量表达式。
答案 1 :(得分:2)
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编译的。
P.S。:如果a被声明为const,那么对于gcc没什么变化,但是对于clang来说,值4不会直接移动,就好像是编译时常量一样。
如果声明a既不是const也不是constexpr,则两个编译器都不能将Parameters :: v [0]视为编译时常量。
答案 2 :(得分:2)
struct Parameters {
static constexpr int n = 2;
static constexpr double v[n] = {4.0, 5.0};
};
据我所知,这个片段本身就是合法的。第7.1.5节C ++ 11标准的[dcl.constexpr]说
constexpr说明符只能应用于......文字类型的静态数据成员的声明
和文字类型在3.9中定义:
类型是文字类型,如果它是:
- 标量类型;或...
- 文字类型数组
因此,就我所知,static constexpr double v[2] = { ... }
肯定是有效的。
关于阵列的成员是constexpr
......我不确定。如果我们宣布
constexpr double d = Parameter::v[1];
然后g ++和clang都可以编译它,但是clang版本无法链接到Parameters::v
的未定义引用。我不知道这是否指向Clang错误,或者构造是否无效。