Re: [问题] constexpr 使用的时机

楼主: Feis (永远睡不着 @@)   2015-05-12 19:00:32
※ 引述《wtchen (没有存在感的人)》之铭言:
: 刚刚学到constexpr这个关键字,不过看了很久不是很了解使用的时机。
: 依照这个网页:
: http://en.cppreference.com/w/cpp/language/constant_expression
: 似乎是可以在等号右边放function的const?
: 不知道前辈们有无进一步的见解?
: 感谢。
大致上 http://en.cppreference.com/w/cpp/language/constexpr 写得还蛮清楚的。
原本也想试着把整个 "常数表示式" (constant expression) 的脉络解释清楚,但是
发现我写了几千字还没写完就放弃了,所以下面先试着讲重点。
对常数表示式只要先记得一个重点: 常数表示式的值可以在编译期被算出,然后当作
一个常数用。
而被 constexpr 所指示的对象就表示该对象的值可以在编译期被算出 [注1],然后当
作一个常数用。
接着我们就可以来讲一下 const 跟 constexpr 的不同。
我觉得需要另外发明 constexpr 这个关键字的重点是下面两个:
1. const 的修饰对象是型别,constexpr 的指示对象是变量或函式名。
2. constexpr 规范的是在编译期 (compile time) 可决定的常数值,而 const 规范
的是在执行期 (runtime) 决定的常数值,两者描述的是不同的概念。
会对 const 跟 constexpr 使用有疑惑主要是因为下面两个延伸规则:
规则一: 当 constexpr 指示的对象是变量名时, 就意味着该变量的型别被 const 修
饰。例如:
constexpr int a = 3;
就等同于:
constexpr const int a = 3;
规则二: 当变量型别被 const 修饰且其值是常数表示式 (编译期就可以决定的值)
时,就意味着该变量名有 constexpr 指示符。例如:
const int a = 3;
就等同于
constexpr const int a = 3
这两个规则让我们觉得 const 跟 constexpr 用谁都可以。
而问题在于 const int a 并不永远等同 constexpr const int a,因为 const 只保
证了执行期的常数性质,不保证其值在编译期可决定。
下面是个反例:
int b = 3;
const int a = b; // 不能写成 constexpr const int a = b;
换句话说,虽然我们知道 a 应该就是 3 了。但是因为语法上没有强制性 (例如可能
某个神祕的地方会偷改到 b 的值),所以这里的 a 不能当编译期的常数用。例如下
面这个例子是不合法的:
int b = 3;
const int a = b;
int c[a]; // 在有 runtime-sized array 的 C++14 以前,这里因为 a 不
// 是常数表示式所以在标准里是不合法的 (除非你使用 VLA 相
// 关 Extension)。
但是改成下面这样又可以:
const int b = 3;
const int a = b;
int c[a]; // 这里的 a 会被成功当作常数表示式作为阵列大小使用
原因可以由上面提过的延伸规则二知道,
const int b = 3; 等同 constexpr const int b = 3;
因为 b 被 constexpr 指示是编译期可以决定的常数值,
所以 const int a = b; 又等同 constexpr const int a = b;
因为 a 被 constexpr 指示是编译期可以决定的常数值,就可以用来作为
阵列大小使用。
这一切真是太隐晦了!
如果当初明确的使用 constexpr指示,则编译器就会帮你确定是否该值是可以在编译
期决定。例如我觉得变量 a 的值应该是在编译期可以决定的常数值,那我就写成
constexpr int a,这样编译器就会帮你检查 a 所设定的值是否是个常数表示式。
例如:
int b = 3;
constexpr int a = b; // 跟 const int a = b 不同,这样写是不合法的。因为你
// 说 a 应该是个编译期可以决定的常数值,但是编译器从
// 语法上不认为。
因为编译错误,所以我们就知道应该要改写成:
constexpr int b = 3;
constexpr int a = b;
至于这里要不要加 const 我是觉得有点多此一举所以主观的就不加了。
结论就是, 如果常数值是在编译期可以决定的, 就用 constexpr。
而使用在函式的基本概念也是一样的,只是不同的 C++ 版本有些差异,细节太多如
果有人有兴趣我再写看看吧。
PS: 这里是从 C++ 出发, 在 C 里面对于 "常数表示式" (constant expression)
和 const 的使用很多都不一样。
注1: 严格来说应该写成 "有可能"
作者: Killercat (杀人猫™)   2015-05-12 19:17:00
这篇写得非常清楚明白,大推
作者: cybelia (@@)   2015-05-12 19:43:00
恍然大悟XD 推一下
作者: wtchen (没有存在感的人)   2015-05-12 20:05:00
受教了!
作者: shadow0326 (非议)   2015-05-12 20:53:00
作者: remizu (remizu)   2015-05-12 21:03:00
好文推
作者: kao50126 (无从)   2015-05-12 21:25:00
推!另外对函式部分也有兴趣
作者: Caesar08 (Caesar)   2015-05-13 00:14:00
推推,好文阿

Links booklink

Contact Us: admin [ a t ] ucptt.com