cpp 类声明中类常量的定义

Definition of class constants in cpp class declaration

提问人:Miguel Hernando 提问时间:4/22/2023 最后编辑:Marcus MüllerMiguel Hernando 更新时间:4/22/2023 访问量:78

问:

尽管原则上似乎只有整数值可以在类的声明中声明为类常量:

struct Foo{
   static const int N=10;
};

在我的代码中,寻找不会强迫我在编译单元中定义浮点常量的替代方案,我已经看到可以放置(并且它有效):

struct Foo
{
    constexpr static float const D1 = 33.8F;
...
 };

事实是,我真的不明白为什么,也不明白为什么标准会支持这种语法,而不是像这样更自然的语法: 静态常量浮点 D1 = 33.8F;

这是正确的吗?请专家解释一下吗?

struct Foo
{
    constexpr static float const D1 = 33.8F;
...
 };

它起作用了

C++ 静态 静态初始化 类常量

评论

2赞 Some programmer dude 4/22/2023
OT:值也意味着 ,因此不需要限定符。constexprconstconst
1赞 Marcus Müller 4/22/2023
尽管原则上似乎只有整数值才能在类的声明中声明为类常量:这是错误的,就像一个简短的测试所证明的那样。
0赞 Some programmer dude 4/22/2023
@MarcusMüller 问题不在于声明变量,而在于初始化(将声明转换为定义)。
3赞 Some programmer dude 4/22/2023
作为解决问题的一种方式:使用您已经发现的。或者做出定义.如constexprinlineinline static float D1 = 33.8f;
0赞 Miguel Hernando 4/22/2023
@MarcusMüller : godbolt.org/z/fEao4G6b3 如您所见,它有效:标准允许整数类型类常量初始化。

答:

3赞 Marcus Müller 4/22/2023 #1

但是您能解释一下不允许声明和定义除 int 之外的一类基本类型的根本原因是什么吗?为什么 constexpr 允许它而 const 不允许?

K.O.解释:历史原因。

无拘无束的投机从下面的剪刀线以下开始

✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄

详细说明:

虽然在实践中,假设整数变量的对齐和放置约束在编译时是已知的,并且在任何给定的硬件平台上都非常明确,但硬件有或没有浮点单元 (FPU) 有相当大的自由度,编译器可以在软件中或使用 FPU(如果可用)实现浮点运算。

现在,FPU 是一头强大的野兽。它支持多种操作模式,例如,在控制应用中,您经常需要饱和数学之类的东西,在这种模式下,尝试存储大于最大值的值只会将值裁剪到最大值。还有一些标志可以启用或禁用在执行除以零或乘以 NaN 等操作时引发中断,这在很大程度上取决于实际的 FPU。C++说,如果支持,您应该支持IEEE754浮动,否则,好吧,做你想做的事?

在这种情况下,您需要运行代码以将 FPU 置于您想要使您刚刚声明的常量实际表示您想要的含义的状态。

所以,在过去,这是猜测,标准化委员会不愿意忍受这种复杂性和可能的陷阱。因此,它不允许初始化类定义中的成员。static float

后来,随着 C++11 的引入,突然之间,所有这些歧义都必须由编译器供应商来清理。 需要有一个(实现定义的)明确值。constexprconstexpr float f = 2.0f * FLOAT32_MAX;

由于 is 有点好(因为它不允许你做一些奇怪的事情,比如不初始化一个常量),所以没有努力扩展 的行为。您的用例是 ,所以使用它!constexprstatic conststatic constconstexpr

C++11 到 C++17 仍然与 和 consorts 不同;floatint

template <typename T, T constant_value>
class default_value_wrapper {
  const T value = constant_value;
};

class container {
  default_value_wrapper<int, 42> def_int;  // OK
  static default_value_wrapper<int, 1337> def_int_constant; //OK

  default_value_wrapper<float, 42.0f> def_float; // doesn't work; float is not allowed for non-type arguments
  static default_value_wrapper<float, 13.37f> def_float_constant; // doesn't work, same reason
};

是非法的。

这种情况只有在 C++20 中才有所改变,当时浮点数也成为结构类型。(不允许使用模板参数对我来说很有意义;每个不同的模板参数都定义了一种新的类型——由于人们对浮点相等性做出了错误的假设,因此使用了“错误”的重载),它只是尖叫着错误)。float

顺便说一下,仅仅因为 C++ 标准说你需要支持结构类型并不意味着编译器支持。目前,似乎正在输掉兼容性竞赛,当前版本(16.0)和当前开发头(主干)都比“对不起,尚不支持'float'类型的非类型模板参数”做得更好。floatclang