类模板const静态成员外部定义为constexpr的标准合规性判定
类模板静态const成员的constexpr定义合规性判定
从C++标准的偏序示例可知,非模板类中可将const静态数据成员在类外部定义为constexpr,以下代码能被所有编译器接受:
struct A { static const double i; }; constexpr double A::i{}; constexpr double j = A::i; // 合法C++,所有编译器均接受
但将该写法应用于类模板时,不同编译器的表现存在分歧:
- 案例#1:gcc接受,clang和msvc拒绝
- 案例#2:将成员类型改为int后,gcc和clang接受,msvc仍拒绝
对应代码如下:
template<class T> class C { public: static const double mem; static const int k; }; template<class T> constexpr double C<T>::mem{}; template<class T> constexpr int C<T>::k{}; int main() { constexpr double i = C<double>::mem; // #1: gcc接受,clang和msvc拒绝 constexpr int j = C<double>::k; // #2: gcc和clang接受,msvc拒绝 }
clang对案例#1的报错信息如下:
<source>:14:22: error: constexpr variable 'i' must be initialized by a constant expression 14 | constexpr double i = C<double>::mem; //#1: gcc accepts but both clang and msvc rejcects | ^ ~~~~~~~~~~~~~~ <source>:14:27: note: read of non-constexpr variable 'mem' is not allowed in a constant expression 14 | constexpr double i = C<double>::mem; //#1: gcc accepts but both clang and msvc rejcects | ^ <source>:5:30: note: declared here 5 | static const double mem; | ^
依据C++标准的合规性判定
案例#1(double类型成员)
根据C++标准,constexpr是变量定义的属性,而非仅声明的属性。类模板中声明的static const double mem,其外部定义constexpr double C<T>::mem{}会将实例化后的成员标记为constexpr对象(constexpr隐含const,与声明的const属性兼容)。根据[expr.const]的规定,读取constexpr对象的左值到右值转换属于常量表达式允许的操作,因此gcc的接受行为符合标准,clang和msvc的拒绝行为不符合标准。
案例#2(int类型成员)
对于static const int k,其外部定义为constexpr的逻辑与案例#1完全一致:实例化后的C<T>::k是constexpr对象,可用于常量表达式初始化。因此gcc和clang的接受行为符合标准,msvc的拒绝行为不符合标准。
内容的提问来源于stack exchange,提问作者user20562802
相关产品推荐
相关产品推荐

