C++11 理解 (四) 之 泛化的常数表示式

C++ 本来就已具备常数表示式(constant expression)的概念。像是 3+4 总是会产生相同的结果并且没有任何的副作用。常数表示式对编译器来说是优化的机会,编译器时常在编译期运行它们并且将值存入程序中。同样地,在许多场合下,C++ 规格要求使用常数表示式。例如在数组大小的定义上,以及枚举值(enumerator values)都要求必须是常数表示式。

然而,常数表示式总是在遇上了函数调用或是对象建构式时就终结。所以像是以下的例子是不合法的:

int GetFive() {return 5;}
 
int some_value[GetFive() + 5]// 欲產生 10 個整數的陣列。 不合法的 C++ 寫法

这不是合法的 C++,因为 GetFive() + 5 并不是常数表示式。编译器无从得知 GetFive 实际上在运行期是常数。理论上而言,这个函数可能会影响全局参数,或者调用其他的非运行期(non-runtime)常数函数等。

C++11引进关键字 constexpr 允许用户保证函数或是对象建构式是编译期常数。以上的例子可以被写成像是下面这样:

constexpr int GetFive() {return 5;}
 
int some_value[GetFive() + 5]// 欲產生 10 個整數的陣列。合法的C++11寫法

这使得编译器能够了解并去验证 GetFive 是个编译期常数。

对函数使用 constexpr 在函数可以做的事上面加上了非常严格的条件。首先,该函数的回返值类型不能为 void。第二点,函数的内容必须依照 "returnexpr" 的形式。第三点,在引数取代后,expr 必须是个常数表示式。这些常数表示式只能够调用其他被定义为 constexpr 的函数,或是其他常数表示式的数据参数。 最后一点,有着这样标签的函数直到在该编译单元内被定义之前是不能够被调用的。

参数也可以被定义为常数表示式值:

constexpr double forceOfGravity = 9.8;
constexpr double moonGravity = forceOfGravity / 6.0;

常数表示式的数据参数是隐式的常数。他们可以只存储常数表示式或常数表示式建构式的结果。

为了从用户自定类型(user-defined type)建构常数表示式的数据参数,建构式也可以被声明成 constexpr。与常数表示式函数一样,常数表示式的建构式必须在该编译单元内使用之前被定义。他必须有着空的函数本体。它必须用常数表示式初始化他的成员(member)。而这种类型的析构式应当是无意义的(trivial),什么事都不做。

复制 constexpr 建构起来的类型也应该被定义为 constexpr,这样可以让他们从常数表示式的函数以值传回。类型的任何成员函数,像是复制建构式、重载的运算符等等,只要他们符合常数表示式函数的定义,都可以被声明成 constexpr。这使得编译器能够在编译期进行类型的复制、对他们施行运算等等。

常数表示式函数或建构式,可以以非常数表示式(non-constexpr)参数唤起。就如同 constexpr 整数字面值能够指派给 non-constexpr 参数,constexpr 函数也可以接受 non-constexpr 参数,其结果存储于 non-constexpr 参数。constexpr 关键字只有当表示式的成员都是 constexpr,才允许编译期常数性的可能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值