引子
decltype類型推導還挺復雜商玫,有時候會出一些奇怪的錯誤,比如下面的程序編譯不過,因為括號里的i推導成引用了神妹。
int main() {
int i;
decltype(i) a;
decltype((i)) b;
}
// cpp.cpp:5:19: error: ‘b’ declared as reference but not initialized
四規(guī)則
當程序員用decltype(e)獲得類型,
- 如果e是一個沒有帶括號的標記符表達式(id-expression)或者類表達式家妆,那么decltype(e)就是e所命名的實體的類型鸵荠。此外,如果e是一個被重載的函數伤极,則會導致編譯時錯誤蛹找。
- 否則姨伤,假設e的類型是T,如果e是一個將亡值(xvalue)庸疾,那么decltype(e)為T&&乍楚。
- 否則,假設e的類型是T届慈,如果e是一個左值徒溪,則decltype(e)為T&。
- 否則金顿,假設e的類型是T臊泌,則decltype(e)為T。
標記符表達式就是常規(guī)理解的表達式串绩,比如int arr[4];缺虐,arr是標記符表達式,但arr[3]就不是礁凡,已經對arr進行了操作高氮。
引子里的例子,a屬于規(guī)則1顷牌,b屬于規(guī)則3剪芍,(i)帶了括號,又實實在在有地址窟蓝、屬于左值罪裹,因此落到了規(guī)則3。
四規(guī)則示例
int main() {
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);
// 規(guī)則1
decltype(arr) var1; // int[5]
decltype(ptr) var2; // int*
decltype(s.d) var4; // double
decltype(Overloaded) var5; // error: decltype cannot resolve address of overloaded function
// 規(guī)則2
decltype(RvalRef()) var6 = 1; // xrvalue, int&&
// 規(guī)則3
decltype(true? i : i) var7 = i; // lvalue int&
decltype((i)) var8 = i; // int&
decltype(++i) var9 = i; // int&
decltype(arr[3]) var10 = i; // int&
decltype(*ptr) var11 = i; // int&
decltype("lval") var12 = "lval"; // const char(&)[9]
// 規(guī)則4
decltype(1) var13; // int
decltype(i++) var14; // int
decltype((Func(1))) var15; // const bool
}
上面的程序覆蓋了四種規(guī)則运挫。
關于var5状共,把void Overloaded(char);那行刪掉就能編譯通過了,沒有重載的函數是可以放在decltype里的谁帕。
另外值得注意的是i++和++i那句峡继,i++得到的是int,++i得到的是int&匈挖。這是因為++i返回的是操作后的結果碾牌,類似(i),不再是標記符表達式儡循,有地址跟i一樣舶吗,落在了規(guī)則3;i++不是i择膝,不是規(guī)則1誓琼,但也沒有地址,落在了規(guī)則4。
打印結果腹侣。
#include <type_traits>
#include <iostream>
using namespace std;
int i = 4;
int arr[5] = {};
int *ptr = arr;
int && RvalRef();
int main(){
cout << is_rvalue_reference<decltype(RvalRef())>::value << endl; // 1
cout << is_lvalue_reference<decltype(true? i : i)>::value << endl; // 1
cout << is_lvalue_reference<decltype((i))>::value << endl; // 1
cout << is_lvalue_reference<decltype(++i)>::value << endl; // 1
cout << is_lvalue_reference<decltype(arr[3])>::value << endl; // 1
cout << is_lvalue_reference<decltype(*ptr)>::value << endl; // 1
cout << is_lvalue_reference<decltype("lval")>::value << endl; // 1
cout << is_lvalue_reference<decltype(i++)>::value << endl; // 0呵扛,不是左值引用也不是右值引用,就是左值
cout << is_rvalue_reference<decltype(i++)>::value << endl; // 0筐带,改成is_integral就能出來1了
}