不带初始值设定项的 constexpr 静态数据成员

constexpr static data member without initializer

本文关键字:constexpr 静态 数据成员      更新时间:2023-10-16
#include <complex>
struct S
{
static std::complex<double> constexpr c;
};

GCC 生成错误,因为缺少初始值设定项。Clang 和 MSVC 不会生成错误。

据我所知,constexpr 静态数据成员必须有一个初始值设定项,即使它是类类型,具有可以在没有参数的情况下调用的构造函数(如本例所示(。不幸的是,我没有最新的C++标准来支持我的假设。

因此,正确的代码应该使用构造函数进行初始化,例如:

struct S
{
static std::complex<double> constexpr c {};
};

谁能证明哪个编译器是对的,哪个是错的?

GCC 是错误的。

GCC 对constexpr变量使用 C++14 规则,这需要提供初始值设定项。这已根据 P0386 更改(粗体文本是新添加的文本(:

在 9.2.3.2p3 中,更改:

如果非易失性非内联const 静态数据成员是整型或枚举类型,则其在类定义中的声明可以指定 b种族或相等初始值设定项,其中作为赋值表达式的每个初始值设定项子句都是常量表达式(5.20(。

文本类型的静态数据成员可以使用 constexpr 说明符在类定义中声明;如果是这样,则其声明应指定一个大括号或等于初始值设定项,其中作为赋值表达式的每个初始值设定项子句都是常量表达式。[ 注意:在这两种情况下,成员都可能出现在常量表达式中。如果在程序中使用 (3.2( 的成员,则仍应在命名空间作用域中定义该成员,并且命名空间作用域定义不应包含初始值设定项。可以在类定义中定义内联静态数据成员,并且可以指定大括号或等于初始值设定项。如果使用 constexpr 说明符声明成员,则可以在没有初始值设定项的情况下在命名空间范围内重新声明该成员(此用法已弃用;请参阅 D.X(。其他静态数据成员的声明不应指定大括号或等于初始值设定项

在这种特殊情况下,有两个答案:

  • 对于 C++14,gcc是正确的(即 constexpr 静态数据成员必须有一个初始值设定项(。
  • 对于 C++17 及以后的版本,gcc 是错误的,因为它拒绝编译一致性代码。

前一种情况 :在草案N3797(C++14(,9.4.2.3(静态数据成员([class.static.data](强调我的(:

可以在类中声明文本类型的static数据成员 使用constexpr说明符进行定义;如果是这样,其声明应 指定一个大括号或等于初始值设定项,其中作为赋值表达式的每个初始值设定项子句都是一个常量表达式

另请参阅:http://en.cppreference.com/w/cpp/language/static#Constant_static_members。

我说"在这种特殊情况下",因为std::complexdouble有专门的LiteralType。因此,上述规则适用。 对于一般(即非文字(类型,请参阅codekaizers答案。

后一种情况 :对于C++17,请参阅xskxzr的答案。

来自 dcl.constexpr#1:

使用constexpr说明符声明的函数或static数据成员 隐式是inline函数或变量

constexprstatic数据成员隐式inline

同样来自class#static.data-3,强调我的:

inlinestatic数据成员可以是 在class定义中定义,并可能指定brace-or-equal-initializer.


因此,海湾合作委员会是错误的。brace-or-equal-initializer不是严格要求的

编号 N4659 C++17 草案