上篇文章讲了模板参数的推导规则,其实auto的推导规则跟模板参数的推导基本上同样的,都是推导参数嘛。好比上篇文章的模板基本结构是:c++
template<typename T> void f(ParamType param); ...... f(expr);
编译器使用expr来推断ParamType
和T
。数组
那么对应在auto推导中,auto就对应了T
,变量的type specifier
就是ParamType
:函数
auto x = 27; const auto cx = x; const auto& rx = x;
这里,cx的type specifier
就是const auto
,rx的type specifier
就是const auto&
.指针
咱们能够想象成在推导auto类型时,编译器就是在作一次模板参数类型推断:code
template<typename T> void func_for_x(T param); func_for_x(27);
template<typename T> void func_for_cx(const T param); func_for_cx(x);
template<typename T> void func_for_rx(const T& param); func_for_rx(x);
在模板参数推导中,咱们根据ParamType
将状况分红了三类。在auto推导中,咱们一样能够根据type specifier
来分红三种状况:orm
type specifier
是一个指针或者引用,但不是universal reference(或者叫forwarding references).type specifier
是一个universal reference。type specifier
既不是指针也不是引用。const auto& rx = x;
上面分析过,再也不赘述。ci
auto&& uref1 = x; // x is int and lvalue, so uref1's type is int& auto&& uref2 = cx; // cx is const int and lvalue, so uref2's type is const int& auto&& uref3 = 27; // 27 is int and rvalue, so uref3's type is int&&
auto x = 27; const auto cx = x;
注意这个Case的状况,假如咱们有个函数返回引用,咱们使用auto接收返回值,若是咱们想改变函数的返回值,那么必须用auto&,而不是auto,由于这里和函数模板参数推断规则同样,是pass-by-value,会忽略引用、const和volatile:编译器
int x = 50; int &f() { return x; } int main() { auto a1 = f(); a1 = 10; // x = 50 auto &a2 = f(); a2 = 20; // x = 20 return 0; }
在函数模板参数推断中讨论了数组和函数做为模板参数的推断状况,在auto类型推断中状况也是相同的:it
const char name[] = "R. N. Briggs"; auto arr1 = name; // arr1's type is const char* auto& arr2 = name; // arr2's type is const char (&)[13]
void someFunc(int, double); auto func1 = someFunc; // func1's type is void (*)(int, double) auto& func2 = someFunc; // func2's type is void (&)(int, double)
从C++11起有4种选择能够定义一个整形变量:io
auto x1 = 27; auto x2(27); auto x3 = { 27 }; auto x4{ 27 };
最后两种是C++11的新特性:统一初始化(uniform initialization),就是这个形成了模板参数推导和auto类型推导的最大区别 :
auto x1 = 27; // type is int, value is 27 auto x2(27); // type is int, value is 27 auto x3 = { 27 }; // type is std::initializer_list<int>, value is { 27 } auto x4{ 27 }; // type is std::initializer_list<int>, value is { 27 }
特殊点在于:若是使用uniform initialization
来进行auto类型推断,那么最终auto推断出的结果是std::initializer_list<int>
因此下面的代码会编译报错:
template <typename T> void f(T param); f({11, 23, 9});
可是若是指定ParamType
为std::initializer_list<T>
,则能够正确的推断T的类型:
template<typename T> void f(std::initializer_list<T> initList); f({ 11, 23, 9 }); // T deduced as int, and initList's type is std::initializer_list<int>
在C++14中,容许将函数返回值和lambda参数声明为auto,可是在这种状况下,auto的类型推断使用的是模板参数类型推断规则:
auto createInitList() { return { 1, 2, 3 }; // error: can't deduce type for { 1, 2, 3 } }
std::vector<int> v; … auto resetV = [&v](const auto& newValue) { v = newValue; }; // C++14 … resetV({ 1, 2, 3 }); // error! can't deduce type for { 1, 2, 3 }
(完)
朋友们能够关注下个人公众号,得到最及时的更新: