以下无法在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]
使用constexpr声明的函数或静态数据成员 说明符隐式地是内联函数或变量
所以我认为它可能与内联变量有关,但在两个编译器下c ++ 1z的以下失败
struct Cls {
static inline const int N = 0;
};
inline const int Cls::N; // note, only one definition here
答案 0 :(得分:13)
在C ++ 17之前,您需要在一个翻译单元中重新声明类外的所有static
变量(通常每个翻译单元都是.cpp
文件,反之亦然,但这不是不需要)。正如您所指出的,C ++ 17引入了inline
类成员变量,static constexpr
变量自动符合条件。正如您在第二个示例中所看到的那样, 允许重新声明类外的inline
变量,但constexpr
之所以例外,因为之前您被允许(并且在这样做的事实,但语法已被弃用。
在[class.static.data] p2中,它允许非内联成员的语法(“在其类定义中声明非内联静态数据成员不是一个定义,可能是 除了cv void之外的不完整类型。未内联定义的静态数据成员的定义 在类定义中,应出现在包含成员类定义的命名空间范围内。“)
在下一段中,该标准允许constexpr
类外声明,并要求它们用于非constexpr
数据(强调添加):
如果非易失性非内联
const
静态数据成员是整数或枚举类型,则其声明 在类定义中可以指定 brace-or-equal-initializer 每个 initializer-clause 是一个赋值表达式是一个 常数表达式(8.20)。该成员仍应定义为 如果在程序中使用了odr-used(6.2),则命名空间范围 命名空间范围定义不应包含初始值设定项。内联 静态数据成员可以在类定义中定义 并可以指定大括号或等于初始化程序。 如果会员是 使用constexpr
说明符声明,可以重新声明 没有初始值设定项的命名空间范围(不推荐使用此用法;请参阅 D.1)。其他静态数据成员的声明不得指定 撑 - 或等于初始值设定
以下是弃用说明,D.1静态constexpr数据成员的重新声明[depr.static_constexpr]:
为了与先前的C ++国际标准兼容,constexpr静态数据成员可能会在以外的地方被冗余重新声明 没有初始化程序的类。不推荐使用此用法。 [示例:
struct A { static constexpr int n = 5; // definition (declaration in C++ 2014) }; constexpr int A::n; // redundant declaration (definition in C++ 2014)
- 结束示例]