第8章 函数探幽
1.内联函数
对于内联函数,编译器将使用相应的函数代码替换函数调用。对于内联代码,程序无需跳到另一个位置处执行代码,再跳回来。因此,内联函数的运行速度比常规函数稍快,但代价是需要占用更多内存。
要使用内联函数,必须在函数声明或函数定义前加上关键字inline,且该函数不能过大或有递归:
inline void print()
{
cout << “Hello World!” << endl;
}
2.临时变量、引用参数和const
当函数的形参中有引用时,如果实参与引用参数不匹配,C++将生成临时变量。如果引用参数是const,则编译器将在下面两种情况下生成临时变量:
- 实参的类型正确,但不是左值(可以通过地址访问的值)。
- 实参的类型不正确,但可以转换为正确的类型。
应尽量将引用参数声明为const数据,因为:
- 使用const可以避免无意中修改数据的编程错误。
- 使用const使函数能够处理const和非const实参,否则只能接受非const数据。
- 使用const引用使函数能够正确生成并使用临时变量。
3.函数返回引用的优点
在下面的语句中:
dup = accumulate(team, five);
如果accumulate()返回一个结构,而不是指向结构的引用,将把整个结构复制到一个临时位置,再将这个拷贝复制给dup。但在返回值为引用时,将直接把team复制到dup,其效率更高。
返回引用的函数实际上是被引用的变量的别名。
4.默认参数
对于带参数列表的函数,必须从右向左添加默认值。也就是说,要为某个参数设置默认值,则必须为它右边的所有参数提供默认值:
int harpo(int n, int m = 4, int j = 5); //VALID
int chico(int n, int m = 6, int j); //INVALID
int groucho(int k = 1, int m = 2, int n = 3); //VALID
5.函数模板
函数模板的定义:
template <typename AnyType>
void Swap(AnyType &a, AnyType &b)
{
AnyType temp;
temp = a;
a = b;
b = temp;
}
其中typename也可以是class。
函数模板也可以进行重载。
6.隐式实例化、显式实例化、显式具体化
如果希望一个函数模板为某一种特定的类型执行不同的操作,则可以使用显式具体化。
编译器使用模板为特定类型生成函数定义时,得到的是模板实例。这种实例化的方式被称为隐式实例化。也可以直接命令编译器创建特定的实例,这种实例化的方式称为显式实例化。
隐式实例化、显式实例化和显式具体化统称为具体化。它们的相同之处在于,它们表示的都是使用具体类型的函数定义,而不是通用描述。
template <typename T>
void Swap (T &, T &); //模板原型
template <> void Swap<job> (job &, job &); //显示具体化
int main()
{
template void Swap<char>(char &, char &); //显式实例化
short a, b;
...
Swap(a, b); //为short类型隐式实例化
job n, m;
...
Swap(n, m); //使用显式具体化的模板
char g, h;
...
Swap(g, h); //使用显式实例化的模板
...
}
编译器看到char的显式实例化后,将使用模板定义来生成Swap()的char版本。对于其他的Swap()调用,编译器根据函数调用中实际使用的参数,生成相应的版本。当编译器看到Swap(n, m)后,将使用为job类型提供的独立定义(显示具体化)。当编译器看到Swap(g, h)后,将使用处理显式实例化时生成的模板具体化。
7.关键字decltype
编写模板函数时,一个问题是并非总能知道应在声明中使用哪种类型:
template<typename T1, typename T2>
void ft(T1 x, T2 y)
{
...
?type? xpy = x + y;
...
}
xpy应为什么类型呢?由于不知道ft()将如何使用,因此无法预先知道这一点。这时就可以利用关键字decltype:
template<typename T1, typename T2>
void ft(T1 x, T2 y)
{
...
decltype(x + y) xpy = x + y;
...
}
decltype()的括号中如果是一个函数调用,实际上并不会调用函数,编译器通过查看函数的原型来获悉返回类型,而无需实际调用函数。
8.后置返回类型
有一个相关的问题是decltype本身无法解决的:
template<typename T1, typename T2>
?type? gt(T1 x, T2 y)
{
...
return x + y;
}
由于无法预先知道将x和y相加得到的类型。好像可以将返回类型设置为decltype(x + y),但此时还未声明参数x和y,它们不在作用域内。为此,C++新增了一种声明和定义函数的语法:
template<typename T1, typename T2>
auto gt(T1 x, T2 y) -> decltype(x + y)
{
...
return x + y;
}
这将返回类型移动到了参数声明的后面。->decltype被称为后置返回类型,decltype也可以改为其他任意的类型。其中auto是一个占位符,表示后置返回类型提供的类型,这是C++11给auto新增的一种角色。