咱們以前使用的typeid運算符來查詢一個變量的類型,這種類型查詢在運行時進行。RTTI機制爲每個類型產生一個type_info類型的數據,而typeid查詢返回的變量相應type_info數據,經過name成員函數返回類型的名稱。同時在C++11中typeid還提供了hash_code這個成員函數,用於返回類型的惟一哈希值。RTTI會致使運行時效率下降,且在泛型編程中,咱們更須要的是編譯時就要肯定類型,RTTI並沒有法知足這樣的要求。編譯時類型推導的出現正是爲了泛型編程,在非泛型編程中,咱們的類型都是肯定的,根本不須要再進行推導。程序員
而編譯時類型推導,除了咱們說過的auto關鍵字,還有本文的decltype。編程
decltype與auto關鍵字同樣,用於進行編譯時類型推導,不過它與auto仍是有一些區別的。decltype的類型推導並非像auto同樣是從變量聲明的初始化表達式得到變量的類型,而是老是以一個普通表達式做爲參數,返回該表達式的類型,並且decltype並不會對錶達式進行求值。函數
int i = 4; decltype(i) a; //推導結果爲int。a的類型爲int。
using size_t = decltype(sizeof(0));//sizeof(a)的返回值爲size_t類型 using ptrdiff_t = decltype((int*)0 - (int*)0); using nullptr_t = decltype(nullptr);
vector<int >vec; typedef decltype(vec.begin()) vectype; for (vectype i = vec.begin; i != vec.end(); i++) { //... }
這樣和auto同樣,也提升了代碼的可讀性。code
在C++中,咱們有時候會趕上一些匿名類型,如:ip
struct { int d ; doubel b; }anon_s;
而藉助decltype,咱們能夠從新使用這個匿名的結構體:字符串
decltype(anon_s) as ;//定義了一個上面匿名的結構體
這也是decltype最大的用途了。編譯器
template <typename _Tx, typename _Ty> auto multiply(_Tx x, _Ty y)->decltype(_Tx*_Ty) { return x*y; }
標記符指的是除去關鍵字、字面量等編譯器須要使用的標記以外的程序員本身定義的標記,而單個標記符對應的表達式即爲標記符表達式。例如:hash
int arr[4]
則arr爲一個標記符表達式,而arr[3]+0不是。編譯
咱們來看下面這段代碼:模板
int i=10; decltype(i) a; //a推導爲int decltype((i))b=i;//b推導爲int&,必須爲其初始化,不然編譯錯誤
僅僅爲i加上了(),就致使類型推導結果的差別。這是由於,i是一個標記符表達式,根據推導規則1,類型被推導爲int。而(i)爲一個左值表達式,因此類型被推導爲int&。
經過下面這段代碼能夠對推導四個規則做進一步瞭解
int i = 4; int arr[5] = { 0 }; int *ptr = arr; struct S{ double d; }s ; void Overloaded(int); void Overloaded(char);//重載的函數 int && RvalRef(); const bool Func(int); //規則一:推導爲其類型 decltype (arr) var1; //int 標記符表達式 decltype (ptr) var2;//int * 標記符表達式 decltype(s.d) var3;//doubel 成員訪問表達式 //decltype(Overloaded) var4;//重載函數。編譯錯誤。 //規則二:將亡值。推導爲類型的右值引用。 decltype (RvalRef()) var5 = 1; //規則三:左值,推導爲類型的引用。 decltype ((i))var6 = i; //int& decltype (true ? i : i) var7 = i; //int& 條件表達式返回左值。 decltype (++i) var8 = i; //int& ++i返回i的左值。 decltype(arr[5]) var9 = i;//int&. []操做返回左值 decltype(*ptr)var10 = i;//int& *操做返回左值 decltype("hello")var11 = "hello"; //const char(&)[9] 字符串字面常量爲左值,且爲const左值。 //規則四:以上都不是,則推導爲本類型 decltype(1) var12;//const int decltype(Func(1)) var13=true;//const bool decltype(i++) var14 = i;//int i++返回右值
這裏須要提示的是,字符串字面值常量是個左值,且是const左值,而非字符串字面值常量則是個右值。
這麼多規則,對於咱們寫代碼的來講不免太難記了,特別是規則三。咱們能夠利用C++11標準庫中添加的模板類is_lvalue_reference來判斷表達式是否爲左值:
cout << is_lvalue_reference<decltype(++i)>::value << endl;
結果1表示爲左值,結果爲0爲非右值。
一樣的,也有is_rvalue_reference這樣的模板類來判斷decltype推斷結果是否爲右值。
參考資料:《深刻理解C++11》