是否在constexpr静态成员的声明中需要constexpr说明符在类外部初始化?

mon*_*506 10 c++ language-lawyer constexpr c++11 c++17

C++17§10.1.5/ 1指出:

constexpr说明符将只应用于一个变量或变量模板的定义或功能或功能模板的声明.使用说明constexpr符声明的函数或静态数据成员 隐式地是内联函数或变量(10.1.6).如果函数或函数模板的任何声明都有一个 constexpr说明符,那么它的所有声明都应该包含说明 constexpr符.

因为类似的段落已在标准中存在C++ 11(§7.1.5/ 1),这是在引述由理查德·史密斯评论,其中他争辩说,C++标准并没有要求constexpr说明符之间匹配声明和变量的定义.在上段的最后一句明确要求constexpr符横跨匹配功能和函数模板的声明,但并没有提及变量声明.

§10.1.5/ 9指出:

constexpr对象声明中使用的说明符将对象声明为const.这样的对象应具有文字类型并应初始化.在任何constexpr变量声明中,初始化的完整表达式应为常量表达式(8.20).

当然,如果我们有一个单独的声明和定义,它们都需要匹配const,无论constexpr指定符是否需要匹配.

§12.2.3.2/ 2-3说:

2在其类定义中声明非内联静态数据成员不是定义,并且可能是除cv 之外的不完整类型void.未在类定义中内联定义的静态数据成员的定义应出现在包含成员类定义的命名空间范围内.在命名空间作用域的定义中,静态数据成员的名称应使用::运算符通过其类名限定.静态数据成员定义中的初始化表达式在其类的范围内(6.3.7).

3如果非易失性非内联const静态数据成员具有整数或枚举类型...如果使用说明constexpr符声明成员,则可以在没有初始化程序的命名空间范围内重新声明该成员 (此用法已弃用;请参阅D.1 ).其他静态数据成员的声明不应指定大括号或等于初始化器.

§D.1/ 1内容如下:

为了与先前的C++国际标准兼容,constexpr 可以在类外部冗余地重新声明静态数据成员而不使用初始化程序.不推荐使用此用法.

从中我们可以收集到,如果使用说明符声明成员constexpr,则命名空间范围定义是多余的,初始化表达式必须与声明配对,并且必须从定义/重新声明中省略.

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

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`
Run Code Online (Sandbox Code Playgroud)

constexprGCC,Clang和MSVC支持对静态数据成员的使用解释,但我被告知这是错误的.

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

如果这实际上是违规,则无法正确定义constexpr其自己的类的静态数据成员,因为类内定义是禁止的,因为类型不完整,并且禁止类外定义包含初始化程序类内声明用说明constexpr符标记.

Jos*_* D. 1

如果我读到这个:

static S const ZERO; // not marked `constexpr`, but still `const`
Run Code Online (Sandbox Code Playgroud)

S::ZERO由于 . 在运行时永远不会改变它的值const

然而:

constexpr S S::ZERO{ 0 }; // implicitly `inline` (if C++17) and `const`
Run Code Online (Sandbox Code Playgroud)

Constant Evaluation完成后,S::ZERO将具有恒定的积分0_value
这会调用您的constexpr constructor

constexpr S(int value = {}) : _value{ value } {}
Run Code Online (Sandbox Code Playgroud)

根据basic.start.static -常量初始化

变量或临时对象的常量初始值设定项o是其完整表达式为常量表达式的初始值设定项,除了 ifo是一个对象之外,这样的初始值设定项也可以 为其及其子对象调用constexpr 构造函数o,即使这些对象属于非文字类类型。

AND expr.const/8.7 -常量求值

名称显示为潜在常量计算表达式的变量,该表达式可以是constexpr 变量,也可以是非易失性 const 限定的整型或引用类型。

所以:

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

我相信你的代码没问题。