上篇文章講了模板參數的推導規則,其實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 }
(完)
朋友們能夠關注下個人公衆號,得到最及時的更新: