C ++17§10.1.5/ 1 陈述:
constexpr
说明符仅适用于a的定义 变量或变量模板或函数或的声明 功能模板。使用。声明的函数或静态数据成员constexpr
说明符隐式地是内联函数或变量 (10.1.6)。如果函数或函数模板的任何声明都有constexpr
说明符,然后它的所有声明都应包含constexpr
说明符。
自a comment by Richard Smith引用的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`
虽然I have been told that this is wrong支持GCC,Clang和MSVC支持对constexpr
使用静态数据成员的这种解释。
在变量声明和定义中使用constexpr
说明符的不匹配是否违规?
如果这实际上是违规,则无法正确定义其自己类的constexpr
静态数据成员,因为类内定义是禁止的,因为类型不完整且属于类外如果类内声明用constexpr
说明符标记,则禁止定义包含初始值。
答案 0 :(得分:1)
如果我读这个:
static S const ZERO; // not marked `constexpr`, but still `const`
由于S::ZERO
, const
在运行期间永远不会更改其值。
然而:
constexpr S S::ZERO{ 0 }; // implicitly `inline` (if C++17) and `const`
Constant Evaluation
已为S::ZERO
完成,其0
的常量值为_value
。
这会调用您的constexpr constructor
:
constexpr S(int value = {}) : _value{ value } {}
根据basic.start.static - 常量初始化:
变量或临时对象
o
的常量初始值设定项是 初始化程序,其完整表达式是常量表达式,除了 如果o
是一个对象,这样的初始值设定项也可以调用 constexpr构造函数用于o
及其子对象,即使这些对象属于非文字类类型。
AND expr.const/8.7 - 常量评估:
一个变量,其名称显示为可能的常量计算值 表达式是 constexpr变量或非易失性 const限定的整数类型或引用类型。
因此:
使用constexpr说明符不匹配是违法行为吗? 跨变量声明和定义?
我相信你的代码很好。