简体   繁体   English

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

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

Example: In header file: 示例:在头文件中:

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

In source file: 在源文件中:

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

This compiles on g++ and allows me to put the initializer list in the source file in stead of the header. 这在g ++上编译,允许我将初始化列表放在源文件中而不是标题中。 (if it were constexpr in the header the compiler requires immediate initialization in the header). (如果它是头文件中的constexpr,则编译器需要在头文件中立即初始化)。 While still allowing the array to be used in constexpr evaluations... 虽然仍允许在constexpr评估中使用该数组......

Is this valid, portable C++ ? 这是有效的,可移植的C ++吗?

I doubt it's compliant. 我怀疑它是否合规。 The declaration and definition are required to be identical AFAIK. 声明和定义必须是相同的AFAIK。

It's certainly not portable. 它肯定不便携。 Although gcc, clang and microsoft cl 2017 accept it, 虽然gcc,clang和microsoft cl 2017接受了它,

ICC reports: ICC报告:

<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

The Right Way 正确的方式

Before we begin the language-lawyering, the correct approach is to do it the other way around. 在我们开始语言律师之前,正确的方法是以相反的方式做到这一点。 In the header file: 在头文件中:

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

And then in a source file: 然后在源文件中:

constexpr int Foo::IntArray[];

If you declare a static constexpr class data member in the class definition, you must initialize it then and there. 如果在类定义中声明static constexpr类数据成员,则必须在那里初始化它。 This is optional for static const data members. 对于static const数据成员,这是可选的。 If you use the static constexpr data member anywhere in the program, you must give a definition like the one above, in exactly one source file, with no initializer. 如果在程序中的任何位置使用static constexpr数据成员,则必须在一个源文件中提供类似上面的定义,而不使用初始化程序。

What the (Draft) Standard Says (草案)标准说的是什么

The example code in the question is bad style, and apparently at least one compiler rejects it, but it does in fact seem to comply with the C++14 draft standard. 问题中的示例代码是错误的样式,显然至少有一个编译器拒绝它,但它实际上似乎符合C ++ 14草案标准。 [ dcl/constexpr ] says: [ dcl / constexpr ]说:

The constexpr specifier shall be applied only to the definition of a variable or variable template, the declaration of a function or function template, or the declaration of a static data member of a literal type. constexpr说明符应仅适用于变量或变量模板的定义,函数或函数模板的声明,或文字类型的static数据成员的声明。 If any declaration of a function, function template, or variable template has a constexpr specifier, then all its declarations shall contain the constexpr specifier. 如果函数,函数模板或变量模板的任何声明都有constexpr说明符,那么它的所有声明都应包含constexpr说明符。

Notice whose declarations are, by omission, not all required to contain the constexpr specifier. 请注意,其声明的遗漏并非都包含constexpr说明符。

Later in the same section: 稍后在同一部分:

A constexpr specifier used in an object declaration declares the object as const . 对象声明中使用的constexpr说明符将对象声明为const Such an object shall have literal type and shall be initialized. 这样的对象应具有文字类型并应初始化。 [...] [...]

But see also [ class.static.data ]: 但另见[ class.static.data ]:

If a non- volatile const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. 如果非易失volatile const static数据成员具有整数或枚举类型,则其在类定义中的声明可以指定大括号或等于初始化器 ,其中作为赋值表达式的每个initializer子句都是常量表达式。 A static data member of literal type can be declared in the class definition with the constexpr specifier; 可以使用constexpr说明符在类定义中声明文字类型的static数据成员; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. 如果是这样,它的声明应指定一个大括号或等于初始化器 ,其中作为赋值表达式的每个initializer子句都是一个常量表达式。 [Note: In both these cases, the member may appear in constant expressions. [注意:在这两种情况下,成员可能会出现在常量表达式中。 — end note ] The member shall still be defined in a namespace scope if it is odr-used in the program and the namespace scope definition shall not contain an initializer. - 结束注释]如果在程序中使用了odr,并且命名空间范围定义不包含初始值设定项,则仍应在命名空间范围内定义该成员。

In this context, the odr in “odr-used” stands for the one-definition-rule and means “whose name appears as a potentially-evaluated expression.” ([basic.def.odr]) The last sentence means that, if you declare, static constexpr int foo = 0; 在这种情况下,“odr-used”中的odr代表单定义规则 ,意味着“其名称显示为潜在评估的表达式。”([basic.def.odr])最后一句意味着,如果你声明, static constexpr int foo = 0; in the class definition, and you will later use it in an expression, such as int x = MyClass::foo; 在类定义中,稍后您将在表达式中使用它,例如int x = MyClass::foo; , then one and only one source file needs to have a line like constexpr int MyClass::foo; ,然后只有一个源文件需要像constexpr int MyClass::foo;这样的行constexpr int MyClass::foo; in it, so the linker knows which object file to put it in. 在其中,链接器知道将哪个目标文件放入其中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM