前文总结过对于模板的类型推导过程,详情参考:Effective Modern C++之Item1。今天再总结一下Effective Modern C++ Item 2 理解auto的类型推导。
auto类型推导过程和模板类型推导几乎遵循同样的推导规则。所以为了便于理解auto类型推导过程,我们可以建立auto和模板函数之间的映射关系。在对Item 1(模板函数类型推导)的总结中,我们的函数模板描述如下:
template<typename T>
void f(ParamType param);
调用过程如下所示:
f(expr); // call f with some expression
在调用函数 f() 的时候,编译器根据expr的类型来推导T和ParamType的类型,当我们用auto来声明一个变量的时候,auto相当于模板中的T,auto和其他类型修饰符(比如const、&)共同构成ParamType
例如:
auto x = 27; //auto 构成了T,同时auto也相当于ParamType
const auto cx = x; //auto 构成了T,const auto 在这里相当于ParamType
const auto& rx = x; //auto 相当于T,const auto& 相当于ParamType
根据映射关系,我们可以用函数模板的方式描述上述用auto进行的变量声明:
template<typename T>
void func_for_x(T param);
func_for_x(27); // auto x = 27
template<typename T>
void func_for_cx(const T param); // const auto cx = x;
func_for_cx(x);
template<typename T>
void func_for_rx(const T& param); // const auto& rx ;
func_for_rx(x);
将auto变量声明映射为函数模板的形式后,就可以按照模板的类型推导规则进行推导了。
在本文一开头的时候,我们说auto类型推导规则几乎是和模板类型推导相同的,也就是说这两者并不是完全相同。那这两者不同的地方在哪呢?
在C++11标准中,支持通过初始化列表的方式对声明的元素赋初值,例如:
auto x3 = {27};
auto x4{27};
当以这种方式声明变量并赋初值时,编译器会将其类型推导为:std::initializer_list<T>类型,所以针对变量x3、x4,类型推导结果如下:
auto x3 = {27}; // type is std::initializer_list<int>,
// value is {27}
auto x4{27}; // 同上
总结:
1、auto类型推导和模板类型推导规则几乎相同。
2、唯一不同的地方是对于已初始化列表方式声明的变量,编译器会将类型推导为std::initializer_list<T>类型。