第一章、类型推导
条款1:理解模板类型推导
模板类型推导的核心就在于模板参数的类型(也就是下文中的
ParamType
)和传入对象类型,下面将其分为三种情况分析。
第一种情况:ParamType
是个非通用的引用或者是一个指针
1.当传递一个const对象给一个引用参数时,往往会期望对象保留其const特性,也就是说,参数变成了const的引用
- 这也是为什么给一个以
T&
为参数的模板传递一个const
对象是安全的——对象的const
特性是模板参数类型推导的一部分
template<typename T>
void f(T& param); // param是一个引用类型
int x = 27; // x是一个int
const int cx = x; // cx是一个const int
const int& rx = x; // rx是const int的引用
f(x); // T是int,param的类型时int&
f(cx); // T是const int,
// param的类型是const int&
f(rx); // T是const int
// param的类型时const int&
2.如果传递一个普通对象给一个const T&
模板参数,那么同样,编译器会自动为传递来的对象添加const
特性
template<typename T>
void f(const T& param); // param现在是const的引用
int x = 27; // 和之前一样
const int cx = x; // 和之前一样
const int& rx = x; // 和之前一样
f(x); // T是int,param的类型是const int&
f(cx); // T是int,param的类型是const int&
f(rx); // T是int,param的类型是const int&
3.在上述的两类传递参数过程中,引用特性(或指针)在类型推导的过程中会被忽略(可以理解为引用只是传递参数的一种手段,与模板内部的参数类型无关)
template<typename T>
void f(T* param); // param是一个指针
int x = 27; // 和之前一样
const int *px = &x; // px是一个指向const int x的指针
f(&x); // T是int, param的类型是int*
f(px); // T是const int
// param的类型时const int*
第二种情况:ParamType
是个通用的引用(Universal Reference)
右值引用(也就是函数模板使用一个类型参数
T
,一个通用的引用参数的申明类型是T&&
)
4.使用了通用的引用,左值参数和右值参数的类型推导大不相同,举例如下:
template<typename T>
void f(T&& param); // param现在是一个通用的引用
int x = 27; // 和之前一样
const int cx = x; // 和之前一样
const int& rx = x; // 和之前一样
f(x); // x是左值,所以T是int&
// param的类型也是int&
f(cx); // cx是左值,所以T是const int&
// param的类型也是const int&
f(rx); // rx是左值,所以T是const int&
// param的类型也是const int&
f(27); // 27是右值,所以T是int
// 所以param的类型是int&&
第三种情况:ParamType
既不是指针也不是引用
5.当ParamType
既不是指针也不是引用,我们把它处理成pass-by-value:
template<typename T>
void f(T param); // param现在是pass-by-value
int x = 27; //和之前一样
const int cx = x; //和之前一样
const int& rx = x; //和之前一样
f(x); //T和param的类型都是int
f(cx); //T和param的类型也都是int
f(rx); //T和param的类型还都是int
- 注意此处
cx
和rx
都是const
类型,但ParamType
却不是const
,这是因为传入的不是cx
和rx
本身(或其引用),而是它们的拷贝版本,cx
和rx
不能被修改和param
能不能被修改是没有关系的。这也就是expr
的常量特性在推导param
的过程中被忽略掉了(expr
不能被修改并不意味着它的一份拷贝不能被修改)
6.考虑到expr
是一个const
的指针指向一个const
对象,而且expr
被通过pass-by-value传递给param
template<typename T>
void f(T param); //param仍然是按值传递的(pass-by-value)
const char* const ptr =