# 总结:C++中的类型推导
使用c++的过程中,与类型推导直接相关的两种情况是template 和auto(c++11),两者的类型推导规则仅有细微不同。
1. template
template 的类型推导可分为三种情况:
1.1. 参数是引用或指针,但不是universal reference
当参数是引用时,理解上可以按照这样的顺序进行类型推导:形参的类型是以实参类型为基础的,通过形参的形式即可得出使模板具现化的类型。
注:1、实际上的顺序是相反顺序的。 2、“为基础”是指不完全相同,还需考虑形参的形式,可能会加上引用/const /volatile
template<typename T> void f(T ¶m); // 指针的情况与引用相似
const int cx = 27;
f(cx); // param的类型是const int&,形参比实参多加上引用,T是const int
const int &rx = cx;
f(rx); // param的类型是const int&, T是const int
template<typename T> void cf(const T ¶m);
int x = cx;
cf(x); // param的类型是const int&, 形参比实参多加上了const, T是int
当参数是指针时,与上述规则类似。
1.2. 参数是通用引用(C++11)
通用引用的情况和参数是引用的情况基本相同,唯一的差别是当参数是通用引用的时候,在“由形参的形式得出使模板具现化的类型”的过程中要考虑引用折叠(C++11)
template<typename T> void f(T &¶m);
int lx = 27; // 左值
f(lx); // param是int&, 使用引用折叠,T是int&
const int &lrx = lx; // 左值
f(lrx); // param是const int&, 使用引用折叠, T是const int&
int &&rrx = 27; // 右值
f(rrx); // param是int&&, T是int
1.3. 参数既不是指针也不是引用时
当参数既不是指针也不是引用时,形参的类型是以实参类型为基础的,会去除引用/const /volatile,通过形参的形式即可得出使模板具现化的类型。
template<typename T> void f(T param);
const int cx = 27;
f(cx); // param是int, 形参比实参少了const, T是int
const int &rcx = cx;
f(rcx); // param是int, 形参比实参少了const和引用, T是int
tempalte<typename T> void cf(const T param);
int x = 27;
int &rx = x;
cf(rx); // param是const int, 形参比实参多了const少了引用, T是int
2.auto
C++11中auto 与template 的类型推导仅在使用了{ } 的时候有所不同:
auto 能为{ } 推导出std::initializer_list<T> ,template 则无法推导类型。
在C++14中,还有一点值得注意:
当auto 应用在返回类型和lambda 表达式的参数时,使用的是template 的类型推导规则。
auto f() { return { 1, 2, 3 }; } // error: 无法推导{ 1, 2, 3 }的类型
auto lmd = [](auto param) { };
lmd({ 1, 2, 3 }); // error: 无法推导{ 1, 2, 3 }的类型