内联函数和constexpr函数
比较两个 string 形参的长度并返回长度较小的 string 的引用,把规模较小的操作定义成函数的好处:
- 阅读和理解 shorterString 函数的调用比读懂等价的条件表达式容易得多。
- 使用函数可以确保行为的统一,每次相关操作都能保证按照同样的方式进行。
- 修改计算过程,修改函数要比先找到等价表达式所有出现的地方再逐一修改更容易。
- 函数可以被其他应用重复利用,省去重新编写的代价。
潜在缺点:
调用函数一般比求等价表达式的值要慢一些。
一次函数调用:调用前要先保存寄存器,并在返回时恢复;可能需要拷贝实参;程序转向一个新的位置继续执行。
内联函数可避免函数调用的开销
将函数指定为内联函数,通常就是将它在每个调用点上“内联地”展开:
cout << shorterString(s1, s2) << endl;
编译过程中展开成类似于下面的形式:
cout << (s1.size() < s2.size() ? s1 : s2) << endl;
从而消除了函数运行时开销。
在函数的返回类型前面加上关键字 inline ,就可以将它声明成内联函数:
inline const string & shorterString(const string& s1, const string& s2) { return s1.size() <= s2.size() ? s1 : s2; }
Note:内联说明只是向编译器发出的一个请求,编译器可以选择忽略这个请求。
一般来说,内联机制用于优化规模小、流程直接、调用频繁的函数。
constexpr函数
constexpr函数是指能用于常量表达式的函数。函数的返回类型及所有形参的类型都是得是字面值类型,而且函数体重必须有且只有一条 return 语句:
constexpr int new_sz() { return 42; } constexpr int foo = new_sz();//正确:foo是一个常量表达式
因为编译器能在程序编译时验证 new_sz 函数返回的是常量表达式,所以可以用 new_sz 函数初始化 constexpr 类型的变量 foo。
执行初始化任务时,编译器把对 constexpr 函数的调用替换成其结果值。为了能在编译过程中随时展开,constexpr 函数被隐式地指定为内联函数。
constexpr 函数体内也可以包含其他语句,只要这些语句在运行时不执行任何操作就行。constexpr 函数中可以有空语句、类型别名以及 using 声明。
允许 constexpr 函数的返回值并非一个常量:
//如果arg是常量表达式时,则scale(arg)也是常量表达式 constexpr size_t scale(size_t cnt) { return new_sz() * cnt; }
当 scale 的实参是常量表达式时,它的返回值也是常量表达式:
int arr[scale(2)];//正确:scale(2)是常量表达式 int i = 2;//i不是常量表达式 int a2[scale(i)];//错误:scale(i)不是常量表达式
给 scale 函数传入一个形如字面值 2 的常量表达式时,它的返回类型也是常量表达式。编译器用相应的结果值替换对 scale 函数的调用。
用一个非常量表达式调用 scale 函数,返回值是一个非常量表达式。如果恰好不是常量表达式,编译器将发出错误信息。
把内联函数和 constexpr 函数放在头文件内
内联函数和 constexpr 函数可以在程序中多次定义。
因为对于某个给定的内联函数或者 constexpr 函数来说,它的多个定义必须完全一致,所以内联函数和 constexpr 函数通常定义在头文件中。

浙公网安备 33010602011771号