条款1(理解模板类型推导)

模板和调用的一般形式:

template void f(ParamType param); f(expr);

从expr来推导T 和ParamType的类型
情况1:ParamType是个指针或引用,但不是个万能引用 推导:
1.若expr具有引用类型,先将引用部分忽略
2.对expr的类型与ParamType的类型进行模式匹配,来决定T的类型
3.左值引用和右值引用相同
左值引用模式如下:
template
void f(T& param); //param是个引用
声明变量:
int x = 27;
const int cx = x;
const int &rx = x;
调用与推导:
f(x); // T的类型是 int,param的类型是int&
f(cx); // T的类型是 const int,param的类型是const int&
f(rx); // T的类型是 const int,param的类型是const int&
const左值引用模式如下:
template
void f(const T& param); //param是个引用
声明变量:
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&
【条款1(理解模板类型推导)】指针模式如下:
template
void f(T* param); //param是个引用
声明变量:
int x = 27;
const int* px = &x;
调用与推导:
f(&x); // T的类型是 int,param的类型是 int*
f(px); // T的类型是 const int,param的类型是const int*
情况2:ParamType是个万能引用 推导:
1.若expr是个左值,T和ParamType都会被推导为左值引用
2.如果expr是个右值,则引用常规的规则
template
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&&
情况3:ParamType既非指针也非引用 当ParamType既非指针也非引用时,我就是所谓的按值传递了:
推导:
1.若expr具有引用类型是,忽略其引用部分
2.忽略引用性后,若expr是const对象或者volatile对象,也忽略
template
void f(T param); //param按值传递
声明变量:
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
param是个完全独立于cx和rx存在的对象----是个cx和rx的一个副本。expr不可修改,并不能断定其副本也不可修改。
情况4:expr是个涉及到const对象的const指针,并且expr按值传给你param
template
void f(T param); //param 按值传递
const char* const ptr = "fun with pointers"; //ptr是个涉及到const对象的const指针
f(ptr); //传递类型为const char* const的实参
位于星号右侧的const将ptr声明为const:ptr不可以指涉到其他内存位置,也不可以被置为null[位于星号左侧的const则将ptr指涉到的对象(那个字符串)为const,即字符串不可修改]。ptr会按值传递,ptr的常量性会被忽略,param的类型会被推导成const char*,即一个可修改的,指涉到一个const字符串的指针。在推导过程中,ptr指涉到的对象的常量性会被得到保留,但其自身的常量性会在以复制的方式创建新指针param的过程中被忽略。
情况5:数组实参 数组类型有别于指针类型,虽然有时他们看起来可以互换。形成这种假象的主要原因就是,在很多语境下,数组会退化成指涉到其首元素的指针。
const char name[] = "j. p. briggs"; //name的类型为const char[13]
const char * ptrToName = name; //数组退化成指针
template
void f(T param);
f(name)
name是个数组,但是T的类型却会被推导为const char*
尽管函数无法声明为真正的数组类型的形参,但是它们却能够将形参声明成数组的引用
template
void f(T& param);
f(name)
T得类型会被推导为const char [13],param的类型会被推导为const char (&)[13]
利用声明数组的引用的能力创造一个模板,用来推导出数组的含有的元素个数:
template constexpr std::size_t arraySize(T (&)[N]) noexcept { return N; } int keyVals[] = {1,2,4,78,5,5,7}; std::array mappedVals;

情况5:数组实参 数组并非c++中唯一可以退化为指针之物。函数类型也同样会退化成函数指针,并且数组的类型推导适用于函数及其向函数指针的退化。
void someFunc(int, double); // someFunc是个函数,其类型为void(int, double)
template
void f1(T param); // 按值传递
template
void f2(T& param); // 按引用传递
f1(someFunc); //param 被推导为函数指针,具体类型为void (*)(int, double)
f2(someFunc); //param 被推导为函数引用, 具体类型为void (&)(int, double)

    推荐阅读