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

时间:2017-04-02 19:33:07

标签: c++

实施例: 在头文件中:

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

在源文件中:

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

这在g ++上编译并允许我将初始化列表放在源文件中而不是标题中。 (如果它是头文件中的constexpr,则编译器需要在头文件中立即初始化)。虽然仍然允许在constexpr评估中使用该数组......

这是有效的,可移植的C ++吗?

2 个答案:

答案 0 :(得分:4)

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

它肯定不便携。虽然gcc,clang和microsoft cl 2017接受它,

国际刑事法院报告:

soap *soap = soap_new();
...
std::stringstream ss;
soap->os = &ss; // assign a stringstream to write output to
soap_write_ns1__Response(soap, &response);
soap->os = NULL; // no longer writing to the stream
std::cout << "The XML is:\n" << ss.str();
...
soap_destroy(soap);
soap_end(soap);
soap_free(soap);

答案 1 :(得分:4)

正确的方式

在我们开始语言律师之前,正确的方法是以相反的方式做到这一点。在头文件中:

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]:

  

如果非volatile const static数据成员是整数或枚举类型,则其在类定义中的声明可以指定大括号或等于初始化程序其中 assignment-expression 的每个 initializer-clause 都是一个常量表达式。可以使用static说明符在类定义中声明文字类型的constexpr数据成员;如果是这样,它的声明应指定一个大括号或等于初始化,其中作为赋值表达式的每个 initializer-clause 是一个不断表达。 [注意:在这两种情况下,成员可能会出现在常量表达式中。 - 结束注释]如果在程序中使用了odr,并且命名空间范围定义不包含初始值设定项,则仍应在命名空间范围内定义该成员。

在这种情况下,“odr-used”中的odr代表 one-definition-rule ,意思是“其名称显示为潜在评估的表达式。”([basic.def。 odr])最后一句意味着,如果你在类定义中声明static constexpr int foo = 0;,稍后你将在表达式中使用它,例如int x = MyClass::foo;,那么只需要一个源文件在其中有一行constexpr int MyClass::foo;,因此链接器知道将它放入哪个目标文件。