静态常量声明,变量的constexpr定义,有效的c ++?

Static const declaration, constexpr definition of variable, valid c++?

本文关键字:有效 定义 constexpr 常量 变量 静态 声明      更新时间:2023-10-16

示例: 在头文件中:

class Foo
{
static const int IntArray[];                         
};

在源文件中:

constexpr int Foo::IntArray[] = { 1, 2, 3, 4 };

这在 g++ 上编译,并允许我将初始值设定项列表放在源文件中而不是标头中。(如果标头中是 constexpr,编译器需要在标头中立即初始化)。同时仍然允许将数组用于 constexpr 评估......

这是有效的便携式C++吗?

正确的方式

在我们开始语言律师之前,正确的方法是反过来做。 在头文件中:

class Foo
{
static constexpr int IntArray[] = { 1, 2, 3, 4 };
};

然后在源文件中:

constexpr int Foo::IntArray[];

如果在类定义中声明static constexpr类数据成员,则必须在当时和那里对其进行初始化。 这对于static const数据成员是可选的。 如果在程序中的任何位置使用static constexpr数据成员,则必须在一个源文件中给出类似于上面的定义,不带初始值设定项。

(草案)标准的内容

问题中的示例代码风格不好,显然至少有一个编译器拒绝它,但实际上它似乎符合 C++14 草案标准。 [DCL/ConstexPR] 说:

constexpr说明符应仅适用于变量或变量模板的定义、函数或函数模板的声明或文本类型的static数据成员的声明。 如果函数、函数模板或变量模板的任何声明具有constexpr说明符,则其所有声明都应包含constexpr说明符。

由于省略,其声明并非全部需要包含constexpr说明符的通知。

在同一节的后面部分:

对象声明中使用的constexpr说明符将对象声明为const。此类对象应具有文本类型,并应进行初始化。[...]

但另请参阅[class.static.data]:

如果非volatileconststatic数据成员是整型或枚举类型,则其在类定义中的声明可以指定大括号或等于初始值设定项,其中作为赋值表达式的每个初始值设定项子句都是常量表达式。可以使用constexpr说明符在类定义中声明文本类型的static数据成员;如果是这样,则其声明应指定一个大括号或等于初始值设定项,其中作为赋值表达式的每个初始值设定项子句都是常量表达式。[注意:在这两种情况下,成员都可能出现在常量表达式中。如果在程序中使用 odr 时,仍应在命名空间作用域中定义该成员,并且命名空间作用域定义不应包含初始值设定项。

在这种情况下,"odr-used"中的 odr 代表一个定义规则,意思是"其名称显示为潜在评估的表达式"。([basic.def.odr]) 最后一句话的意思是,如果你在类定义中声明static constexpr int foo = 0;,并且稍后将在表达式中使用它,例如int x = MyClass::foo;,那么只有一个源文件需要有一行类似constexpr int MyClass::foo;,所以链接器知道要把它放在哪个对象文件中。

我怀疑它是否合规。声明和定义必须是相同的 AFAIK。

它当然不是便携式的。尽管 gcc、clang 和 Microsoft cl 2017 接受它,

国际商会报告:

<source>(6): error: member "Foo::IntArray" (declared at line 3) was previously not declared constexpr
constexpr int Foo::IntArray[] = { 1, 2, 3, 4 };
^
compilation aborted for <source> (code 2)
Compiler exited with result code 2