c++ - 现在允许重新定义 constexpr 静态数据成员吗? (但不是内联常量)?

标签 c++ c++14 c++17

以下在c++14的gcc和clang下都编译失败,但是用c++1z编译成功:

struct Cls {
  static constexpr int N = 0;
};
constexpr int Cls::N;
constexpr int Cls::N;

C++14 错误是可以预见的:redefinition of ‘constexpr const int Cls::N’

什么改变使这合法?我发现:

n4659 10.1.5 [dcl.constexpr]

A function or static data member declared with the constexpr specifier is implicitly an inline function or variable

所以我认为这可能与内联变量有关,但以下两种编译器下的 c++1z 都失败了

struct Cls {
  static inline const int N = 0;
};
inline const int Cls::N; // note, only one definition here

最佳答案

在 C++17 之前,您需要在一个翻译单元中重新声明类外的所有 static 变量(通常每个翻译单元都是一个 .cpp 文件反之亦然,但这不是必需的)。正如您所指出的,C++17 引入了 inline 类成员变量,并且 static constexpr 变量自动限定。正如您在第二个示例中看到的那样,您不允许在类外部重新声明 inline 变量,但是 constexpr 出现了异常,因为之前你被允许(实际上是被要求)这样做,但语法已被弃用。

在 [class.static.data]p2 中,它允许非内联成员的语法(“在其类定义中声明非内联静态数据成员不是定义,可能是 cv void 以外的不完整类型。未内联定义的静态数据成员的定义 在类定义中应出现在包含成员类定义的命名空间范围内。”)

在下一段中,该标准允许 constexpr 类外声明,并要求它们用于非 constexpr 数据(已添加重点):

If a non-volatile non-inline 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 (8.20). The member shall still be defined in a namespace scope if it is odr-used (6.2) in the program and the namespace scope definition shall not contain an initializer. An inline static data member may be defined in the class definition and may specify a brace-or-equal-initializer. 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.

这是弃用说明,D.1 重新声明静态 constexpr 数据成员 [depr.static_constexpr]:

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. [ Example:

struct A {
  static constexpr int n = 5; // definition (declaration in C++ 2014)
};
constexpr int A::n; // redundant declaration (definition in C++ 2014)

— end example ]

关于c++ - 现在允许重新定义 constexpr 静态数据成员吗? (但不是内联常量)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45019980/

相关文章:

c++ - 没有对 std::index_sequence 中的包扩展进行诊断

c++ - 为什么 C++11/14 中的 std::forward 没有 std::move_if_noexcept 对应项?

c++ - 区分右值 View 和右值容器

c++ - 在 C++ 中取消引用该指针是否有效?

c++ - #define 的 "Declaration does not declare anything"错误

c++ - -> 之后带有类型别名的推导指南

如果类的成员,C++ 数组会导致崩溃

c++ - 查找满足查询条件的geohashes的算法

c++ - 我怎样才能让 GCC 在 ROM 中放置一个 C++ constexpr?

c++ - 如何将右值引用参数传递给 C++ 中的模板 operator() 函数?