C++ 为什么我们需要将函数标记为constexpr?
C++11允许使用C++ 为什么我们需要将函数标记为constexpr?,c++,c++11,constexpr,C++,C++11,Constexpr,C++11允许使用constepr说明符声明的函数在常量表达式(如模板参数)中使用。对允许的内容有严格的要求constexpr;本质上,这样一个函数只封装一个子表达式,而不封装其他任何东西。(编辑:这在C++14中是宽松的,但问题仍然存在。) 为什么需要关键字呢获得了什么? 它确实有助于揭示接口的意图,但它通过保证函数在常量表达式中可用来验证该意图。编写constexpr函数后,程序员仍必须: 编写一个测试用例,或者确保它实际用于常量表达式中 记录哪些参数值在常量表达式上下文中有效 与揭示意图相
constepr
说明符声明的函数在常量表达式(如模板参数)中使用。对允许的内容有严格的要求constexpr
;本质上,这样一个函数只封装一个子表达式,而不封装其他任何东西。(编辑:这在C++14中是宽松的,但问题仍然存在。)
为什么需要关键字呢获得了什么?
它确实有助于揭示接口的意图,但它通过保证函数在常量表达式中可用来验证该意图。编写constexpr
函数后,程序员仍必须:
constexpr
装饰函数可能会增加错误的安全感,因为在忽略中心语义约束的情况下会检查相切的语法约束
简言之:如果函数声明中的
constexpr
仅仅是可选的,会不会对语言产生不良影响?或者对任何有效的程序都有影响吗?没有关键字,编译器无法诊断错误。编译器将无法告诉您该函数在语法上是无效的constexpr
。虽然你说这会带来“虚假的安全感”,但我认为最好尽早发现这些错误。我们可以不使用constexpr
,但在某些情况下,这会使代码更简单、更直观。例如,我们有一个类,它声明了一个具有某个引用长度的数组:
template<typename T, size_t SIZE>
struct MyArray
{
T a[SIZE];
};
现在看看它与constexpr
的关系:
template<typename T, size_t SIZE>
constexpr
size_t getSize (const T (&a)[SIZE]) { return SIZE; }
int a1[100];
MyArray<decltype(*a1), getSize(a1)> obj;
防止客户端代码期望超出您的承诺
假设我正在编写一个库,其中有一个函数当前返回一个常量:
awesome_lib.hpp
:
如果不需要constexpr
,作为客户机代码的作者,您可能会离开并执行以下操作:
客户端应用程序cpp
:
#包括
#包括
std::array my_array;//需要CT模板参数
int my_c_数组[f()];//需要CT阵列尺寸
然后,如果我将f()
更改为从配置文件返回值,您的客户机代码将被破坏,但我不知道我有破坏您的代码的风险。实际上,只有当您遇到一些生产问题并重新编译时,您才会发现这个额外的问题阻碍了您的重建
通过只更改f()
的实现,我就可以有效地改变接口的用法
相反,C++11以后的版本提供了constexpr
,因此我可以指出,客户机代码可以对保持constexpr
的函数有合理的期望,并且可以这样使用它。我知道并认可这种用法作为我的界面的一部分。就像在C++03中一样,编译器继续保证客户端代码不会依赖于其他非constexpr
函数来防止上面的“不需要的/未知的依赖”场景;这不仅仅是文档,而是编译时强制执行
值得注意的是,这继续提供C++的趋势,为传统的预处理器宏的使用提供更好的替代方案(考虑代码< >定义f 4 < /C>),以及客户端程序员如何知道lib程序员是否认为它是公平的游戏来改变为“代码”>定义f配置([ f ] ] /代码>,以其众所周知的“邪恶”。例如在语言的名称空间/类范围系统之外
为什么没有“显然”never const函数的诊断?
我认为这里的混乱是由于constepr
没有主动确保有任何一组参数的结果实际上是编译时常量:相反,它要求程序员对此负责(否则标准中的§7.1.5/5认为程序格式不正确,但不要求编译器发出诊断)。是的,这很不幸,但它没有删除上述constexpr
实用程序
这样,也许有助于从“代码的什么地方> CONEXPRPR < /代码>的角度来考虑,“为什么我可以编译一个不能永远返回const值的代码< CONTXPRPR <代码>函数?” 答:因为需要进行详尽的分支分析,这种分析可能涉及任意数量的组合。诊断可能会在编译时和/或内存方面花费过多,甚至超出任何可想象的硬件的能力。此外,即使在实际情况下,也必须准确地诊断这种情况,这是一个全新的难题编译器编写者的rms(他们对自己的时间有更好的利用)。这也会对程序产生影响,例如从
constexpr
函数中调用的函数的定义需要在执行验证时可见(以及函数调用的函数等)
同时,缺少constepr
继续禁止将其用作常量值:严格性在sans-constepr
方面。如上文所示,这很有用
与非'const'成员函数的比较
防止constepr
而缺少int x[f()]
则防止const
-它们都确保客户端代码不会硬编码不需要的依赖关系const x;x.f();
- 在这两种情况下,您不希望编译器自动确定
-ness:const[expr]
- 当您已经可以预见到一个
对象上的成员函数将演变为修改可观察值breaki时,您不会希望客户端代码调用该对象上的成员函数const
template<typename T, size_t SIZE> constexpr size_t getSize (const T (&a)[SIZE]) { return SIZE; } int a1[100]; MyArray<decltype(*a1), getSize(a1)> obj;
int i = 5; const int j = i; // ok, but `j` is not at compile time constexprt int k = i; // error
inline int f() { return 4; }
#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
- 当您已经可以预见到一个