以下代码在 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
在 C++17 之前,您需要重新声明所有static
类外的变量恰好在一个翻译单元中(通常每个翻译单元是一个.cpp
文件,反之亦然,但这不是必需的)。正如您所指出的,C++17 引入了inline
类成员变量,以及static constexpr
变量自动限定。你是not允许重新申报inline
类外部的变量,正如您在第二个示例中看到的那样,但有一个例外constexpr
因为以前您被允许(实际上是必需的)这样做,但语法已被弃用。
在 [class.static.data]p2 中,它允许非内联成员的语法(“在其类定义中非内联静态数据成员的声明不是定义,并且可以是
除 cv void 之外的不完整类型。未内联定义的静态数据成员的定义
类定义中的应出现在包含成员的类定义的命名空间范围中。”)
在下一段中,该标准允许constexpr
类外声明并要求它们用于非constexpr
数据(强调):
如果非易失性非内联const
静态数据成员是整型或枚举类型,其声明
在类定义中可以指定大括号或等于初始化器在
其中每个初始化子句那是一个赋值表达式是一个
常数表达式 (8.20)。该成员仍应定义在
命名空间范围(如果在程序中使用了 odr(6.2))并且
命名空间范围定义不应包含初始化器。内联
静态数据成员可以在类定义中定义
并且可以指定一个大括号或等于初始化器. 如果该会员是
声明与constexpr
说明符,它可以在中重新声明
没有初始化程序的命名空间范围(此用法已弃用;请参阅
D.1)。其他静态数据成员的声明不得指定大括号或等于初始化器.
这是弃用注释,D.1 静态 constexpr 数据成员的重新声明 [depr.static_constexpr]:
为了与之前的 C++ 国际标准兼容,constexpr 静态数据成员可以在外部多余地重新声明。
没有初始化程序的类。这种用法已被弃用。 [Example:
struct A {
static constexpr int n = 5; // definition (declaration in C++ 2014)
};
constexpr int A::n; // redundant declaration (definition in C++ 2014)
—结束示例 ]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)