[C++] 特殊用途语言特性

三种函数相关的语言特性:默认实参、内联函数、constexpr函数

默认实参

某些函数有这样一些形参,在函数的很多次调用中它们都被赋予一个相同的值,此时,我们把这个反复出现的值称为函数的默认实参。调用含有默认实参的函数时,可以包含该实参,也可以忽略该实参。

typedef string::size_type sz;
string screen(sz ht = 24, sz wid = 80, char backgrnd = ' ');

其中我们为每个形参都提供了默认实参,默认实参作为形参的初始值出现在形参列表中。

我们可以为一个或多个形参定义默认值,

需要注意的是:一旦某个形参被赋予了默认值,它后面的所有形参都必须有默认值。

使用默认形参调用函数

如果我们想使用默认形参,只要在调用函数的时候忽略该实参就可以了。

函数调用时实参按其位置解析,默认实参负责填补函数调用缺少的尾部实参(靠右侧位置)。如果想要覆盖backgrad的默认值,必须先为ht和wid提供实参。

所以在设计默认实参的函数时,应该合理设置形参的顺序,尽量让不怎么使用默认值的形参出现在前面,而让那些经常使用默认值的形参出现在后面。

默认实参声明

对于一个函数声明,通常的习惯就是将它放在头文件中,并且一个函数只声明一次,但是多次声明同一个函数也是合法的。

在给定的作用域中一个形参只能被赋予一次默认实参,换句话说,函数的后续声明只能为之前那些没有默认值的形参添加默认实参,而且该形参右侧的所有形参必须都有默认值。

string screen(sz, sz, char = ' ');
// 表示高度和宽度的形参没有默认值
string screen(sz, sz, char = '*');
// 错误,重复声明,不能修改一个已经存在的默认值
string screen(sz = 24, sz = 80, char);
// 正确,添加默认实参

通常应该在函数声明中指定默认实参,并将该声明放在合适的头文件中。

默认实参初始值

局部变量不能作为默认实参,除此之外,只要表达式的类型能转换为形参所需的类型,该表达式就能作为默认实参

// wd def ht的声明必须在函数之外
sz wd = 80;
char def = ' ';
sz ht();
string screen(sz = ht(), sz = wd, char = def);

string window = screen();
// 调用screen(ht(), 80, ' ');

用作默认实参的名字在函数所在作用于内解析,而这些名字的求值过程发生在函数调用时

void f2() {
    def = '*';
    // 改变了默认实参值
    sz wd = 100;
    // 隐藏了外部定义的wd,但是没有改变实参值。
    window = screen();
}
// 调用 screen(ht(), 80, '*');

f2内部改变了def值,所以对screen的调用会传递这个更新过的值,

虽然我们函数还声明了一个局部变量用于隐藏外部的wd,但是该局部变量与传递给screen的默认实参没有任何关系。

内联函数

把函数指定为内联函数,通常就是将它在每个调用点上“内联地”展开。避免函数调用的开销

举个例子

inline const string& shorterString(const string& s1, const string& s2) {
    return s1.size() <= s2.size() ? s1 : s2;
}

cout << shorterString(s1, s2) << endl;
// 该调用在编译过程中展开成类似于下面的形式
cout << (s1.size() <= s2.size() ? s1 : s2) << endl;

内联说明只是向编译器发出的一个请求,编译器可以选择忽略这个请求

constexpr函数

constexpr函数是指能用于常量表达式的函数。

需要遵循以下几项约定:

1、函数的返回类型及所有形参的类型都得是字面值类型

2、函数体中必须有且只有一条return语句

3、函数提可以包含其他的语句,但是这些语句不能在运行期起作用

4、函数可以不返回常量,但是在调用的时候实参必须传入常量表达式

constexpr int new_sz() { return 42; }
constexpr int foo = new_sz();

new_sz()无参数,返回值是常量表达式。

new_sz()可以初始化constexpr类型的变量foo

在编译时constexpr函数被隐式指定为内联函数

constexpr返回值并非一个常量

// 如果arg是常量表达式,则scale(arg)也是常量表达式
constexpr size_t scale(size_t cnt) { return new_sz() * cnt; }

int arr[scale(2)];
// 正确、scale(2)是一个常量表达式
int i = 2;
int a2[scale(i)];
// 错误、scale(i)不是一个常量表达式
原文地址:https://www.cnblogs.com/immjc/p/8183718.html