关于c ++:constexpr静态成员声明所需的constexpr说明符是否在类外部初始化?

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的说明符在变量的声明和定义之间匹配。上面段落的最后一条语句显式要求constexpr说明符在函数和函数模板声明之间匹配,但没有提到变量声明。

§10.1.5/9规定:

A constexpr specifier used in an object declaration declares the
object as const. Such an object shall have literal type and shall be
initialized. In any constexpr variable declaration, the
full-expression of the initialization shall be a constant expression
(8.20).

当然,如果我们有一个单独的声明和定义,它们都需要在const中匹配,而不管constexpr说明符是否需要匹配。

§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 cv void. 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.

从中我们可以得出,如果成员是用constexpr说明符声明的,那么名称空间范围定义是多余的,初始值设定项表达式必须与声明成对出现,并且必须从定义/重新声明中省略。

作为一个完整的例子,我提供了它自己的文本类型类(不能在类中初始化)的静态成员的情况:

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支持对constexpr与静态数据成员一起使用的解释,尽管我被告知这是错误的。

在变量声明和定义中使用不匹配的constexpr说明符是否违反规定?

如果这实际上是一个冲突,那么就不可能正确地定义它自己类的constexpr静态数据成员,因为类内定义是被禁止的,因为类型不完整,并且如果类内声明用constexpr说明符标记,则禁止类外定义包括初始值设定项。


如果我读到这个:

1
static S const ZERO; // not marked `constexpr`, but still `const`

由于const的原因,S::ZERO在运行时不会改变其值。

然而:

1
constexpr S S::ZERO{ 0 }; // implicitly `inline` (if C++17) and `const`

Constant Evaluation用于S::ZERO_value具有常整数值0。这将调用您的constexpr constructor

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 if o is an object, such an initializer may also invoke
constexpr constructors for o 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?

我相信你的密码没问题。