条款二 了解auto类型推断
基础知识
除了一处例外,auto的类型推断与template一样。存在一个直接的从template类型推断到auto类型推断的映射
三类情况下的推断如下所示:
// case 1 const auto& rx = x; // rx -> int // case 2 auto&& uref1 = x; // uref1 -> int& auto&& uref2 = cx; // uref2 -> const int& auto&& uref3 = 27; // uref3 -> int&& // case 3 auto x = 27; // x -> int const auto cx = x; // x -> int
对于数组和函数,有如下推断:
const char name[] = "R. N. Briggs"; auto arr1 = name; // arr1 -> const char* auto& arr2 = name; // arr2 -> const char(&)[13] void someFunc(int, double); auto func1 = someFunc; // func1 -> void (*)(int, double) auto& func2 = someFunc; // func2 -> void (&)(int, double)
但是在使用初始化列表(std::initializer_list)的情况下,auto的类型推断会有问题
auto x = 27; // x1 -> int auto x2(27); // x2 -> int auto x3 = {27}; // x3 -> std::initializer_list<int> auto x4{27}; // x4 -> std::initializer_list<int>
列表初始化是auto与template类型推断的唯一区别,template函数推断中不能使用列表形式的初始化{}
auto x = {11, 23, 9}; template<typename T> void f(T param); f({11, 23, 9}); // wrong! template<typename T> void f(std::initializer_list<T> initList); f({11, 23, 9}); // T -> int, initList -> std::initializer_list<int>
C+14可以使用auto来推断函数返回类型,并且lambda可以在形参声明中使用auto,但是此处的auto使用template类型推断而非auto类型推断,所以返回列表初始化将报错
auto createInitList() { return {1, 2, 3}; } // error! std::vector<int> v; auto resetV = [&v](const auto& newValue) {v = newValue}; resetV({1, 2, 3}) // error!
总结
- auto类型推断总是和template类型推断一样,但是auto类型推断把列表初始化解析成std::initializer_list,template类型推断则不然
- 在函数返回类型以及lambda形参中的auto,采用template类型推断而非auto类型推断