auto : 類型推導. 在使用c++的時候會常用, 就像在考慮STL時迭代器類型, 寫模板的時候使用auto能少寫代碼, 也能幫助咱們避免一些隱患的細節.c++
auto
型別推導要求必須在定義時初始化, 畢竟須要根據對象的類型推導左值對象的型別.auto j; // error. 必須初始化 auto i = 0; // i 推導型別爲 int vector<int> v; auto vv = v.cbegin(); // vv 推導型別爲 const int*
auto
型別推導會忽略引用和頂層const, 因此要對對象加上想要的修飾.const int ci = 0; auto i = ci; // i 推導型別爲 int, 忽略了頂層const int &ri = i; auto ii = ri; //ii 推導型別爲 int, 忽略了引用
()
和=
對變量初始化, C++11增長了對定義的對象初始化的方法,可使用{}
對變量初始化c11以前的初始化方法編程
int i(0); // i 初始化 0 int j = 0; // j 初始化 0
c11後的初始化方法數組
auto i(0); auto j = i; // 支持c11前 auto ii{0}; // 使用 {} 進行初始化, 可是auto推導只能接受一個參數 auto jj = { 0 }; // jj 的推導型別爲 initializer_list<int>型別
上面jj的推導竟然不是int型別, 而是 initializer_list<int>
, 這不能怪auto推導出問題, 這主要是後者的對象初始化就是使用={}
, 能夠說是auto推導的是最精確的型別. 無論新添的初始化方法, 找一個習慣的就好了.函數
auto
最多見的就是與for
聯用, 特別是類型特別複雜的時候. 可是auto又有多種選擇, 如 : auto, auto &等, 不一樣的選擇其效率也不同.oop
auto
, 即 for(auto i:range) . 這使range中的每個元素都會產生一個副本, 因此即便修改了 i 也不會實際影響到range.const auto
, 及for(const auto i : range). 這也會是range的每個元素產生一個副本, 可是這個副本竟不能被修改.auto &
, 即for(auto &i : range). 引用, 由於i 直接引用range裏面的元素, 因此並不會產生一個副本, 可是 i 的修改也會影響range裏元素的值. 一般咱們須要修改range是會考慮用到.const auto&
, 即for(const auto &&i : range). i 直接引用range裏面的元素, 因此並不會產生一個副本, 而且i 也不能修改. 通常初始化的是一個左值時並且是讀取range裏的元素時都是用const auto&
而不用auto
, 由於前者不會產生副本, 效率要高. 固然通常初始化的是一個左值時效率低, 可是若是是右值仍是使用const auto
效率高, 由於const auto &
須要把 i 存儲在內存中的一個位置,間接訪問會更消耗時間auto&&
, 即for(auto &&i : range). 若是初始化是左值, 那麼 i 就是左值引用, 若是初始化是右值, 那麼 i 就是右值引用,還有const auto &
, 固然具體的選擇仍是看具體的狀況而定.code
最後, 當用auto
推導多維數組的時, 保證除最內層循環外, 其餘的外層循環都應該是引用類型, 不然很容易出錯, 即 :對象
int a[10][10][10]; for (const auto &i : a) for(const auto &j : i) for(const auto k : j) ;
auto
初始化在平臺上還有一點好處, 好比 :vector<int> v; unsigned size = v.size(); // size()返回size_t型別 auto sizet = v.size();
在32的平臺unsigned
表明的是32位, size_t
是32位, 在64的平臺unsigned
表明的也是23位, 可是size_t
倒是64位, 這樣平臺差別可能就會帶來問題, 使用auto
代替就沒有這樣的問題.內存
不過只有這幾點可能不會讓人心動, 下面咱們還有auto的好處.ci
還記得在前言中個說過調用STL最好使用auto
推導型別, 若是你還記得map
與pair
嗎? 是這樣 map<pair<key, type>>
? 仍是map<pair<const key, type>>
? 答案是最後一種, 那麼如今咱們就來分析的使用auto
推導仍是顯示型別比較好.get
int main() { std::map<string, std::function<type(type, type)>>func = { { "+", [](auto i, auto j)->auto {return i + j; } }, { "-", [](auto i, auto j)->auto {return i - j; } }, { "*", [](auto i, auto j)->auto {return i * j; } }, { "/", [](auto i, auto j)->auto {return i / j; } } }; for (const auto &i : func) ; for(const std::pair<string, std::function<type(type, type)>> &pa : func) ; system("pause"); exit(EXIT_SUCCESS); }
看到上面的例子毫無問題, 可是深究起來顯示型別仍是些不完美. 咱們知道map的key
不能被改變, 因此顯示型別的string
與map的const string
不是匹配, 編譯器就會將map對象都會產生一個臨時對象再隱式的轉爲string
, 等等. 是否是注意到有一點了, 爲了型別匹配賦值會產生臨時變量, 那豈不是每一循環都會產生一個臨時變量, 可是auto
型別推導就是精確匹配的, 不會產生臨時變量.
可能以爲將顯示型別的key改成const string
就能解決這個問題了, 確實是這樣, 可是若是沒有注意到這一點細節, 那就會損失效率了, 使用auto能夠徹底不想這些問題啊.
固然使用顯示型別仍是型推導看實際也看我的, 不是必要.
auto
不能被聲明爲返回值,auto
不能做爲形參,auto
不能被修飾爲模板參數. 那麼這裏auto
還能怎麼和函數關聯起來? 能.
auto放在函數名前面告訴編譯器,真正的返回值在函數聲明以後. 簡單說auto能夠做爲返回值佔位符來使返回值後置.
就像這樣來寫.
auto Return(std::size_t N) -> std::size_t { return N; }
既然c++規定能夠這樣寫確定有其意義. 其實這個寫法主要用於template
中, 當返回值的類型是一個模板類型時使用, 而返回值類型經過decltype
來推導.
這裏就解釋一下decltype
的簡單運用. , decltype
也是相似與auto
的關鍵字, 都可以進行參數類型推導, 可是decltype
必需要接受一個參數, 以下:
int i = 1; decltype(i) j = 1;
auto
與模板函數連用時用模板參數做爲返回值. 由於編譯器並不能直接推斷出返回值爲類型參數的實際類型, 因此在STL中採用traits
編程解決這個問題, 這裏時另外一種實現方法.
首先看一個錯誤的例子:
template<class T1, class T2, class T3> T3 fun(T1 t1, T2 t2) {...}
T3的類型要在函數返回的時候才能知道, 而函數這樣寫就必需要編譯期間就要知道返回值類型. 因此編譯器會報錯.
如下這樣寫就是正確的, 可是必須保證編譯器能推導出類型.
template<class T1, class T2, class T3> T1 fun(T1 t1, T3 t3) {...}
使用auto將返回值類型放在最後, 就是告訴編譯器真正的返回值在編譯後動態獲取, 而auto在這裏的做用也稱爲返回值佔位
template<class T1, class T2> auto fun(T1 t1, T2, t2) -> decltype(*t1) {...}
以上能夠將返回類型放在函數尾作尾置是C11中的要求, 可是C14已經能夠將返回型別放推導在函數頭. 如 :
template<class T1> decltype(auto)fun() {...} // 這樣的寫法同上式同樣
雖然規定可以這樣寫, 有時爲了兼容也仍是寫成尾置.
咱們可使用auto
來推斷出new
對象的類型, 可是侷限在於, 必須對new
出來的對象進行單一的初始化.
auto i = new int; // 這中寫法根本沒有用到auto的推導哦, 由於new的類型已經肯定了 auto i = new auto(1); // 這裏就是用到了auto推導 auto size = new auto; // error, 不能推導出size的類型 auto j = new auto(1,2); // error, 只能接收一個初始化值
在const
中咱們分析到頂層const
會被忽略, 因此auto
是沒法推斷出頂層const, 即 :
auto i = new const auto(1); // 這裏auto並無推導出頂層const, 因此i的類型其實是int const auto j = new const auto(1); // 只有顯示的定義j的類型是const
若是想直接推導出頂層const的話, 最好仍是decltype
進行推導.
注意 : auto
推導只能推導出int, double等, 不能推導出short類型.
本節對C11的auto用法作了一個淺顯的分析, 分別對使用auto
的好處, 定義時注意{}
對象也必須初始化, auto
在與for連用的時候要根據實際參數肯定選擇哪一種實現, 這樣效率纔會達到最大, 固然通常都使用const auto&
和auto&&
. 最後還對auto
與函數返回值關聯, 能夠將返回型別放在函數名尾也能夠, 這樣的作法通常在模板中將模板參數做爲返回值才考慮用, 平時也沒必要這樣定義函數.
參考 :
<< Effective Modern C++ >>