[英]C++ Why can I initialize a static const char but not a static const double in a class definition?
这是两行代码:
static const double RYDBERG_CONST_EV = 13.6056953;
static const char CHAR_H_EDGE = '-';
第二行编译没有错误,第一行不编译。 (错误: 'constexpr' needed for in-class initialization of static data member...
)
解决方案显然是在类型之前添加关键字constexpr
。 这是必需的,因为double
不是“整数类型”。 但为什么整数和浮点类型之间的行为不同?
我不相信这是有充分理由的,除非它在历史上有所增长。
在C ++ 11之前,积分类型的例外是可取的,因为人们希望将它们用作数组大小。 这与整数const
被视为常量表达式的另一个例外相关。 浮点类型不存在的异常。
const int ni = 10;
const float nf = 10.0f;
int numbers1[(unsigned) ni]; // perfectly fine in all versions of C++
int numbers2[(unsigned) nf]; // error in all versions of C++
当C ++ 11引入constexpr
,它可以做任何const
integral类型的特殊外壳可以做的事情等等。 对于任何文字类型,它的工作方式相同。 因此,给定一个优秀的工具,不需要将整数类型的现有规则扩展到浮点。
今天,整体类型的特殊外壳大多是早期较暗日的遗留物。 它无法从语言中删除,因为这样做会破坏依赖于这种特殊外壳的现有代码,但是由于constexpr
原因,通过添加更多的例外情况会使得语言更加复杂化,这一点几乎没有什么好处。 人们应该被期望迁移到constexpr
而不再担心旧的问题。 我认为这是一个非常合理的决定,但你当然可以争辩说应该做出另一个决定。
正如TC所评论的那样,有一个关于这个问题的(非) 缺陷报告 ,委员会确认行为不会改变,人们应该开始使用constexpr
。
1826.
const
表达式中的const
浮点数条:5.20 [expr.const]状态:NAD发布者:Ville Voutilainen日期:2014-01-04
用
const
初始化的const
整数可以用在常量表达式中,但是用const
初始化的const
浮点变量不能。 这是故意的,与C ++ 03兼容,同时鼓励constexpr
的一致使用。 然而,有些人发现这种区别令人惊讶。还观察到允许
const
浮点变量作为常量表达式将是ABI突破性变化,因为它将影响λ捕获。一种可能性是在常量表达式中不推荐使用
const
积分变量。附加说明,2015年4月:
EWG要求CWG允许在常量表达式中使用
const
浮点变量。理由(2015年5月):
CWG认为当前的规则不应该改变,并且希望浮点值参与常量表达式的程序员应该使用
constexpr
而不是const
。
对于措辞,§[class.static.data] / 3说:
- 如果非易失性const静态数据成员是整数或枚举类型,则它在类定义中的声明可以指定一个大括号或大小为初始化器 ,其中作为赋值表达式的每个initializer子句都是一个常量表达式(5.20) )。 可以使用constexpr说明符在类定义中声明文字类型的静态数据成员 ; 如果是这样,它的声明应指定一个大括号或等于初始化器,其中作为赋值表达式的每个initializer子句都是一个常量表达式。
(我的)。 请注意,在整数类型的情况下,静态数据成员可以 (而不是必须 )进行初始化(您始终可以将其置于类定义之外)。 另外,在类定义中进行初始化的唯一其他方法是通过constexpr。
关于允许在类定义中初始化整数类型(也在C ++ 98中)的推理(恕我直言)是为了实现这样的非常简单的模式:
class Foo {
static const size_t arrayLen = 42;
int foo[arrayLen];
};
没有体内初始化将无法实现。
众所周知:
static const
integral type members可以在类定义中初始化。
static constexpr
成员可以在类定义中初始化
double
不是一个整数类型,应标记为constexpr
。
在机器中生成的可执行文件可以在浮点表示计算不同的其他机器中运行。 积分常量表达式不会改变。
将对象标记为static
表示所有观察者都可以知道它,并使其成为const
表示该值不会改变。 编译器可以生成值(例如314)并将其放入只读部分,因为范围是在标准中定义的。
另一方面, double
不在标准中,并且在类定义中不能对其进行远程检查和在编译时存储的值。 人们可能很容易得到不同的目标文件,其对象具有不同的static const double
值,从而破坏了ODR。
这是一个简单的例子:
struct foo
{
static char const a = 1/11; // everyone gets 0 at compile-time
};
那么你会说,但这可能发生在双打和初看,就像这样
struct foo
{
static double const y=1.0/11.0; // the true value is 0.090909...
};
似乎可证实的,但在一台机器双表示将0.09091
在另一个0.090909091
。
使用constexpr
允许向编译器说明在编译时可以获得验证这一点所需的输入。 但是,实际评估可以在运行时进行 。
由于C ++编译器生成的目标文件可以移动到具有不同浮点表示的机器,因此必须告知必须在编译期间进行此检查以确保一致性。
问题是XY问题的典型例子。 而不是问,“ 为什么我必须用constexpr
标记任何东西? ”给出了一个拼图char
- float
。 现在的问题是,“ 为什么我们必须使用constexpr
作为非整数类型 ?”, 在这里你可以找到你的答案 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.