在Item1中介绍了C++98的模板类型推导,而C++11中引入的auto其类型推导规则和模板类型是如出一辙的。在Item1中提到的模板类型推导规则可以总结为如下形式:
template<typename T>
void f(`参数类型` param)
f(var)
根据参数类型和传入的var的类型的不同,推导的规则也相应不同,那么auto是如何和模板推导规则关联呢?
auto x = 27 //对应Item1中的Case3,x的类型就是int
int& z = x;
const int y = 19;
auto cx = x; //对应Item1中的Case3,cx的类型就是int,忽略了y的CV限制符和引用等
const auto& rx = z; //对应Item1中的Case1,rx的类型是const引用类型,忽略z的引用
auto&& rrx = 27 //对应Item1中的Case2,rrx的类型int&&
参数类型 param = var
auto可以总结为上面这种形式。根据赋值操作右边的var类型,和变量名左边的参数类型结合起来进行推导。在Item1中还提到了两个额外的类型推导,一个是数组类型,另外一个是函数类型。对应到auto则如下:
const char name[] = "test";
auto arr1 = name; //arr1的类型是const char*类型
auto& arr2 = name; //arr2的类型是const char(&)[5]
void someFunc(int,doubel);
auto func1 = someFunc; //void(*)(int,double)
auto& func2 = someFunc; //void(&)(int,double)
除了上面提到的推导规则外,auto还有一个和模板类型推导不一样的地方。这也是本节Item需要关注的。在C++11中引入了统一初始化列表,相对应的则是std::initializer_list<T>
模板类型。
auto x1 = {1,2,3}; //此时x1被推导为std::initializer_list<T>
因为初始化列表是模板类型,因此所有的元素必须是同一类型,否则会初始化失败。对应到模板类型推导如下:
auto x = {11,23,9}
template<typename T>
void f(T param);
f(x); //编译错误,无法进行推导。
模板类型推导居然无法识别初始化列表,只能写成下面这种形式才可以进行推导。
template<typename T>
void f(std::initializer_list<T> param);
至于为什们,其实我也不清楚,也没有找到相关的资料,就只能当做一个规则记着吧。但是auto也不是那么完美,如果auto
用于推导函数的返回类型,auto是不能推导初始化列表的。
auto createInitList() { //C++14支持这种写法,C++11中需要结合decltype
return { 1,2 ,3 };
}
除了不能作为函数返回值外,还不能作为lambda的参数,注意是lambda的参数,普通函数的参数是可以的,C++11中不支持lambda的参数使用auto,C++14开始支持。
auto lda = [](const auto& v) {};
lda({1,2,3}); //编译出错,无法推导初始化列表。