Effective Modern C++ 系列之 條款2: auto
Effective Modern C++ 系列之 條款2: auto 型別推導
在理解模板型別推導規則後,那麼auto型別推導不是什麼問題了,除了一個奇妙的例外情況以外,auto型別推導就是模板型別推導.
template<typename T>
void f(ParamType param);
而一次呼叫形如:
f(expr);
在f呼叫中,編譯會根據expr來推導T和ParamType的型別.
當變數採用auto來宣告時, auto就扮演了模板中T的角色, 而變數的型別修辭詞則扮演的是ParamType的角色.
例如:
auto x = 27; (1) x的修飾詞就是auto自身 .
const auto cx = x; (2) cx的修飾詞 const auto .
const auto& rx = x; (3) rx的修飾詞 const auto& .
在C++中auto型別推導和模板型別推導是一模一樣的(除了在一個例外情況下),可以利用模板型別推導規則模擬auto型別推導過程如下:
template<typename T> //模擬auto型別推導過程.
void func_for_x(T param);
func_fox_x(27); // 推導得出param的型別就是X的型別.
template<typename T>
void func_for_cx(const T param);
func_for_cx(x) // 推導得出param的型別就是cX的型別.
template<typename T>
void func_for_rx(const T& param);
func_for_rx(rx); //推導得出的param的型別就是rx的型別.
1. auto型別推導與模板型別推導一模一樣的規則.
採用auto進行變數宣告中,型別修飾詞取代ParamType,所以也存在三種情況:
1.1 型別修飾詞是指標或引用,但不是萬能引用.
auto x = 27 ;
const auto cx = x ;
const auto& rx = x ;
1.2 型別修飾詞是萬能引用.
auto&& uref1 = x; // x的型別是int, 且是左值,所以uref1的型別是int&。
auto&& uref2 = cx; // cx的型別是const int, 且是左值. 所以uref2的型別是const int&.
auto&& uref3 = 27; // 27的型別是int, 且是右值. 所以uref3的型別是int&&.
1.3 型別修飾詞既非指標也非引用.
在條款1中,陣列和函式名字如何在非引用修飾詞的前提下退化成指標,也同樣適合auto型別推導
const char name[] = "J. P. Briggs"; //name的型別是const char[13].
auto arr1 = name; // arr1的型別是const char*.
auto& arr2 = name; // arr2的型別const char(&)[13].
void someFunc(int, double); //someFunc是個函式,型別是void(int, double).
auto func1 = someFunc; //func1的型別是void(*)(int, double).
auto& func2 = someFunc; //func2的型別是void(&)(int, double).
2. auto型別推導與模板型別推導不同存在差異的情況.
auto宣告變數的初始化表示式使用{}時,推導所得的型別屬於std::initializer_list
auto x = {1,2,3,4,3.0} //錯誤,推導不出std::initializer_list<T>中T.
模板傳入一個{}的初始化表示式,型別推導就會失敗
auto x = {1,2,3} //x的型別是std::initializer_list<int>
template<typename T>
void f(T param)
f({1,2,3,4}); // 無法推導T的型別.
注意: auto 和 模板型別推導真正的唯一區別在於,auto會假定用大括號括起來的初始化表示式代表一個std::initializer_list,但模板型別推導卻不會.
在函式返回值或者lambda式的形象中使用auto,意思是使用模板型別推導而非auto型別推導.
auto createInitList {
return {1,2,3,4}; //錯誤,無法為{1,2,3}完成型別推導.
}
std::vector<int> v;
...
auto resetv = [&v](const auto& newValue) { v = newValue }; //c++14
...
restv({1,2,3}); //錯誤!無法為{1,2,3}完成型別推導.
4. 總結
- 在一般情況下,auto型別推導和模板型別推導是一模一樣的,但是auto型別推導會假定用大括號括起來的初始化表示式代表一個std::initializer_list,但是模板型別推導卻不會.
- 在函式返回值或lambda式的形參中使用auto,意思是使用模板型別推導而非auto型別推導.
5. 驗證程式碼
#include <boost/type_index.hpp>
#include <vector>
#include <iostream>
using namespace std;
using namespace boost;
using boost::typeindex::type_id_with_cvr;
int main(int argc, char** argv) {
auto&& x = 12;
std::cout << "param =" << type_id_with_cvr<decltype(x)>().pretty_name() << std::endl;
return 0;
}
本文學習《 Effective Modern C++ 》一書整理的學習筆記
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2157/viewspace-2825370/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 學懂現代C++——《Effective Modern C++》之型別推導和autoC++型別
- More Effective C++ 條款2 (轉)C++
- 【Effective Modern C++】索引C++索引
- More Effective C++ 條款4 (轉)C++
- More Effective C++ 條款19 (轉)C++
- More Effective C++ 條款6 (轉)C++
- More effective C++ 條款14 (轉)C++
- More Effective C++ 條款15 (轉)C++
- More Effective C++ 條款3 (轉)C++
- More Effective C++ 條款11 (轉)C++
- More effective C++ 條款13 (轉)C++
- More effective C++ 條款12 (轉)C++
- More Effective C++ 條款5 (轉)C++
- More Effective C++ 條款一 (轉)C++
- More Effective C++ 條款17 (轉)C++
- More Effective C++ 條款18 (轉)C++
- More Effective C++ 條款20 (轉)C++
- More Effective C++ 條款21 (轉)C++
- More Effective C++ 條款22 (轉)C++
- More Effective C++ 條款23 (轉)C++
- More Effective C++ 條款24 (轉)C++
- More Effective C++ 條款25 (轉)C++
- More Effective C++ 條款7 (轉)C++
- More Effective C++ 條款8 (轉)C++
- More Effective C++ 條款28(中) (轉)C++
- More effective c++ 條款10(上) (轉)C++
- More effective c++ 條款10(下) (轉)C++
- More Effective C++ 條款27(下) (轉)C++
- More Effective C++ 條款28(上) (轉)C++
- More Effective C++ 條款28(下) (轉)C++
- More Effective C++ 條款26(下) (轉)C++
- 學懂現代C++——《Effective Modern C++》之轉向現代C++C++
- Effective C++ 條款08_不止於此C++
- Effective STL之條款2:謹防容器無關程式碼的假象 (轉)
- Effective c++條款11:在operator=中處理“自我賦值”C++賦值
- [讀書筆記][effective C++]條款30-inline的原理筆記C++inline
- margin系列之keyword auto
- C++::My Effective C++C++