问题 constexpr比const更“恒定”吗?


C ++编程语言第四版 - Bjarne Stroustrup :(强调我的)

2.2.3。常量 

在一些地方,语言规则需要常量表达式   (例如,数组边界(§2.2.5,§7.3),案例标签(§2.2.4,§9.4.2),一些   模板参数(第25.2节)和使用constexpr声明的常量。   在其他情况下,编译时评估对性能很重要。    独立于性能问题,不可变性(具有不可更改状态的对象)的概念是一个重要的设计问题   (第10.4节)。

Stroustrup似乎在这里暗示 constexpr 确保物体的不变性比传统的更好 const 宣言。它是否正确?有没有办法 constexpr 可以更安全/更不稳定 const,或者Stroustrup只是意味着因为有方法可以使用 constexpr 不支持的 const (看到 constexpr真的需要吗?),在这些情况下,可以确保使用不变性 constexpr


8037
2017-12-01 04:51


起源

相关 在C ++ 11之前的“常量表达式” - Shafik Yaghmour
我无法找到我的书副本来检查背景,但由于constexpr仍然不能保证不变性,如果这是他的建议,我会感到惊讶。从你的简短引语来看,我认为他只是说不变性很重要,而不是constexpr比const更好地实现这一点,反之亦然。 - Jonathan Wakely
@JonathanWakely - 也许你是对的,它只是扔在那里,因为一般主题是他所谓的 不变性。我现在把整段放在那里 - 这是对材料的总结 constexpr所以我明白有一些特别的东西 constexpr就像那里提到的其他要点一样,但也许不是。 - Vector
@JonathanWakely我认为使其含糊不清的是在特定陈述中引用这些部分的方式,它们似乎意味着OP所要求的内容。我同意我不相信他的建议,但在阅读了几次后,即使在整个背景下也不是最明确的陈述。 - Shafik Yaghmour


答案:


他在本节开头说:

C ++支持两种不可变性的概念

他列出了 常量 和 constexpr,我不相信他是在试图这么说 constexpr 确保不变性比 常量 他们只是有不同的功能,虽然我承认句子引用部分的事实 10.4  常数表达式  似乎暗示,这种解释与文本的其他部分不一致。

一个变量 const 在该范围内是不可变的但可能不是 const 在更大的范围内(例如,函数的const引用参数他说,这可能是他试图制造的一种微妙的区别 const

主要用于指定接口

constexpr

这主要用于指定常量,以允许将数据放在只读存储器中

任何变量都是 constexpr 应该在编译时进行评估,因此可以在需要常量表达式的情况下使用,而传递为的变量 const 一个功能不一定是 const 超出范围。

当然你可以扔掉 常量性 运用 const_cast 但试图修改一个 const 对象是未定义的行为,因此它不会变得不可变 constexpr 从这个意义上说,来自 草案C ++ 11标准 部分 7.1.6.1  cv资格赛

任何在其生命周期内修改const对象的尝试(3.8)都会导致未定义的行为

乔纳森威克利注意到了 constexpr 像变量一样 常量 变量可以有一个 可变成员 但该成员不能用于常量表达式。

注意一个 constexpr 变量也是 常量,来自草案C ++ 11标准部分 7.1.5  constexpr说明符

对象声明中使用的constexpr说明符声明了   对象为const。


10
2017-12-01 05:45



他在该部分的开头清楚地说明了...... 是的,明白了。这就是问题的一部分:你如何修改价值 myConst 在声明中: const int myConst=999?编译器强制执行 const。也许通过用指针颠覆它?这是不可能的 constexpr?是否存在“更不可变”的东西 constexpr 我不确定我理解这个答案,除非变量传递为 const 进入函数,因此无法在函数中修改它们。 - Vector
“const的对象在该范围内是不可变的,但在较大的范围内可能不是const” 从技术上讲,对象是const还是not,period。可以通过“const访问路径”(例如通过const指针)使用非const对象,但是对象本身仍然是非const的。不可变的并不仅仅意味着“现在不会改变,但可能会在以后改变”。 - Jonathan Wakely
@JonathanWakely这是我在睡觉之前写的那个,修复了。 - Shafik Yaghmour
正如MikeMB的回答所示,声明constexpr的变量仍然可以包含可变成员,因此不是真正的编译时常量。 - Jonathan Wakely
@JonathanWakely这是一个有趣的边缘案例,我重写在那一点上不那么绝对。 - Shafik Yaghmour


const不能确保按位常数,例如,因为类可以有可变成员(典型的例子是内部同步的私有互斥),你可以 const_cast 从指针中取出常量。

constexpr 声明一个可以在编译时计算的常量变量或函数,这意味着对对象的内容有一些限制,但我相信,关键字本身在运行时没有提供任何额外的保证。 const。 也可以看看 这个 讨论。


5
2017-12-01 09:49



使用constexpr声明的对象仍然可以拥有可变成员,即使在Richard Smith提出的问题解决后也是如此(DR 1405)它只是不能用于常量表达式。所以你说得对,这意味着constexpr仍然不能保证不变性。你可以 const_cast远离宣布的东西的常数 constexpr (但是尝试修改它仍然是未定义的,就像声明的变量一样 const) - Jonathan Wakely
这就是我所说的“关键字本身在运行时与const相比没有提供任何额外的保证”。你想说,我应该删除链接?我添加了它,因为它是我找到的第一个来源,它明确指出了这一点 constexpr 对象可以有可变成员,从而支持我的观点“constexpr 没有比这更稳定 const“ - MikeMB
我认为保持它是有用的 - Jonathan Wakely
我不清楚的是,你的评论是否意在支持或纠正我的答案。 - MikeMB
我试图用额外的细节支持它......但是你说得对,我不是很清楚,对不起! - Jonathan Wakely