防止客户端代码期望超过您的承诺
假设我正在编写一个库并在其中有一个当前返回常量的函数:
awesome_lib.hpp
:
inline int f() { return 4; }
如果constexpr
不需要,您 - 作为客户端代码的作者 - 可能会离开并执行以下操作:
client_app.cpp
:
#include <awesome_lib.hpp>
#include <array>
std::array<int, f()> my_array; // needs CT template arg
int my_c_array[f()]; // needs CT array dimension
然后我应该更改f()
说从配置文件返回值,您的客户端代码会中断,但我不知道我冒着破坏您的代码的风险。实际上,可能只有当您遇到一些生产问题并重新编译时,您才会发现这个额外的问题使您的重建工作受挫。
通过仅更改 的实现,f()
我将有效地更改接口的使用。
相反,C++11 及更高版本提供constexpr
,因此我可以表示客户端代码可以对保留的函数有合理的期望 a constexpr
,并按原样使用它。 我知道并赞同将这种用法作为我界面的一部分。 就像在 C++03 中一样,编译器继续保证客户端代码不会构建为依赖于其他非constexpr
函数,以防止上述“不需要/未知的依赖”情况;这不仅仅是文档 - 它是编译时执行。
值得注意的是,这延续了 C++ 的趋势,即为预处理器宏的传统用途提供更好的替代方案(考虑#define F 4
,以及客户端程序员如何知道 lib 程序员是否认为更改为公平游戏#define F config["f"]
),以及他们众所周知的“邪恶”,例如因为在语言的命名空间/类范围系统之外。
为什么没有“明显”从不 const 函数的诊断?
我认为这里的混乱是由于constexpr
没有主动确保结果实际上是编译时 const 的任何参数集:相反,它要求程序员对此负责(否则标准中的 §7.1.5/5认为程序格式错误,但不需要编译器发出诊断)。是的,这很不幸,但它并没有删除constexpr
.
所以,也许从“有什么意义”constexpr
这个问题切换到考虑“为什么我可以编译一个constexpr
永远不会真正返回 const 值的函数?”会有所帮助。.
答:因为需要详尽的分支分析,可能涉及任意数量的组合。诊断的编译时间和/或内存成本可能过高——甚至超出任何可以想象的硬件的能力。此外,即使实际上必须准确诊断此类情况,对于编译器编写者(他们可以更好地利用他们的时间)来说,这也是一个全新的蠕虫罐头。还会对程序产生影响,例如从函数内部调用的函数的定义constexpr
需要在执行验证时可见(以及函数调用的函数等)。
同时,缺乏继续constexpr
禁止用作 const 值:严格性在 sans- constexpr
side 上。如上图所示,这很有用。
与非`const`成员函数的比较
constexpr
防止int x[f()]
而缺乏const
防止const X x; x.f();
- 它们都确保客户端代码不会硬编码不需要的依赖项
在这两种情况下,您都不希望编译器const[expr]
自动确定 -ness:
它们的不同之处在于编译器强制const
在成员函数中使用其他成员const
,但不强制使用编译时常量结果constexpr
(由于实际的编译器限制)