Is the constexpr specifier required on the declaration of a constexpr static member initialized outside of the class?
C++ 17×101.5/1状态:
The
constexpr specifier shall be applied only to the definition of a
variable or variable template or the declaration of a function or
function template. A function or static data member declared with the
constexpr specifier is implicitly an inline function or variable
(10.1.6). If any declaration of a function or function template has a
constexpr specifier, then all its declarations shall contain the
constexpr specifier.
在Richard Smith的评论中引用了C++ 11(7.7.1.5/1)中的一个类似段落,他认为C++标准不要求EDCOX1×0的说明符在变量的声明和定义之间匹配。上面段落的最后一条语句显式要求
§10.1.5/9规定:
A
constexpr specifier used in an object declaration declares the
object asconst . Such an object shall have literal type and shall be
initialized. In anyconstexpr variable declaration, the
full-expression of the initialization shall be a constant expression
(8.20).
当然,如果我们有一个单独的声明和定义,它们都需要在
§12.2.3.2/2-3说:
2 The declaration of a non-inline static data member in its class
definition is not a definition and may be of an incomplete type other
than cvvoid . The definition for a static data member that is not
defined inline in the class definition shall appear in a namespace
scope enclosing the member’s class definition. In the definition at
namespace scope, the name of the static data member shall be qualified
by its class name using the :: operator. The initializer expression in
the definition of a static data member is in the scope of its class
(6.3.7).3 If a non-volatile non-inline
const static data member is of
integral or enumeration type... If the member is declared with the
constexpr specifier, it may be redeclared in namespace scope with no
initializer (this usage is deprecated; see D.1). Declarations of other
static data members shall not specify a brace-or-equal-initializer.
第二部分1读:
For compatibility with prior C++ International Standards, a
constexpr
static data member may be redundantly redeclared outside the class
with no initializer. This usage is deprecated.
从中我们可以得出,如果成员是用
作为一个完整的例子,我提供了它自己的文本类型类(不能在类中初始化)的静态成员的情况:
1 2 3 4 5 6 7 8 9 10 | struct S { static S const ZERO; // not marked `constexpr`, but still `const` constexpr S(int value = {}) : _value{ value } {} int const _value; }; constexpr S S::ZERO{ 0 }; // implicitly `inline` (if C++17) and `const` |
gcc、clang和msvc支持对
在变量声明和定义中使用不匹配的
如果这实际上是一个冲突,那么就不可能正确地定义它自己类的
如果我读到这个:
1 | static S const ZERO; // not marked `constexpr`, but still `const` |
由于
然而:
1 | constexpr S S::ZERO{ 0 }; // implicitly `inline` (if C++17) and `const` |
1 | constexpr S(int value = {}) : _value{ value } {} |
根据basic.start.static-常量初始化:
A constant initializer for a variable or temporary object
o is an
initializer whose full-expression is a constant expression, except
that ifo is an object, such an initializer may also invoke
constexpr constructors foro and its subobjects even if those objects are of non-literal class types.
和expr.const/8.7-常量计算:
a variable whose name appears as a potentially constant evaluated
expression that is either a constexpr variable or is of non-volatile
const-qualified integral type or of reference type.
因此:
Is it a violation to have non-matching use of the constexpr specifier
across variable declarations and definitions?
我相信你的密码没问题。