实施例: 在头文件中:
class Foo
{
static const int IntArray[];
};
在源文件中:
constexpr int Foo::IntArray[] = { 1, 2, 3, 4 };
这在g ++上编译并允许我将初始化列表放在源文件中而不是标题中。 (如果它是头文件中的constexpr,则编译器需要在头文件中立即初始化)。虽然仍然允许在constexpr评估中使用该数组......
这是有效的,可移植的C ++吗?
答案 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;
,因此链接器知道将它放入哪个目标文件。