decltype
引入的原因之一是在函式模板中遇到如下情形:
template <typename T1, typename T2>
void foo(T1 a, T2 b)
{
?type? tmp = a + b;
}
此時,tmp型別該定義為哪種呢?我們知道基礎資料型別相加時會自動進行型別提升,直接用T1或者T2都是不合適的。此時就需要使用新的關鍵字decltype
。
template <typename T1, typename T2>
void foo(T1 a, T2 b)
{
decltype(a + b) tmp = a + b;
}
由編譯器自己在編譯過程中推導,當然也可以用auto代替。decltype
關鍵字的作用是獲取提供給它的引數的資料型別。可以是變數,表示式,函式呼叫等。使用decltype
的格式如下:
decltype(expression) var;
確定decltype推匯出來的型別按如下步驟:
-
第一步:如果expression是一個沒有額外括號擴起來的變數,則var的型別和該變數型別相同,包括cv限定符;
int x; int y; int z[10]; int &rx = x; const int *pi; decltype(x) a; //int型別 decltype(rx) b = y; //int &型別 decltype(pi) c; //const int* 型別 decltype(z) d; //int[10]型別 //除了一般變數,也可以是函式指標(起始也是一般變數,就是指標而已) int foo(){return 0;} decltype(foo) myFoo; //int(*)()型別,注意這裡表示式是函式名
-
第二步:如果expression是函式呼叫,則var的型別和函式返回值一樣;
int foo(){return 0;} decltype(foo()) fooRet; //int型別
處理函式呼叫時,它的原理是直接檢視函式宣告中的返回值型別,所以甚至都不需要看到函式實現:
int foo(); int main() { decltype(foo()) var; //int型別 return 0; }
-
第三步:如果expression是用額外括號括起來的左值,那麼var的型別就是對應型別的引用,包括cv限定符;
int x; int y; const int a = 1; const int b = 2; decltype((x)) ry = y; //int &型別,如果不做賦值操作,會提示錯誤 decltype((a)) rb = b; //const int &型別,如果不做賦值操作,會提示錯誤 rb = 1; //報錯,因為rb是const int &型別
-
第四步:如果expression是表示式,則var型別與其型別一樣:
int x = 1; int &y = x; decltype(x + 1) a; //int型別 decltype(x + y) b; //int型別 decltype(3) c; //int型別 decltype(4L) d; //long型別 decltype(5.0f) e; //float型別 int foo(); decltype(foo() + 3) f; //int型別
有一個比較特殊的型別
void
型別,我們知道void型別用在函式宣告上,主要給函式返回值或者引數用。所以有以下變態寫法:void foo(); decltype(foo()) bar(decltype(foo())) { }
不過這種用法好像毫無意義。
還有一種情況,如下:
template <typename T1, typename T2>
?type? Add(T1 a, T2 b)
{
return a + b;
}
如果定義了一個模板函式,將兩個不同型別的變數相加,並且返回他們的和。那此時返回值型別該是那種?或許我可以加入第三個型別解決:
template <typename T0, typename T1, typename T2>
T0 Add(T1 a, T2 b)
{
return a + b;
}
如果呼叫如下:
char a = 1;
short b = 2;
int sum;
sum = Add<int, char, short>(a, b);
sum = Add(a, b); //不支援型別推導,提示無法推導型別T0
好像也沒啥問題,但是需要我們知道不同型別相加時型別提升的規則,這無疑是很麻煩的。於是decltype
被引入了,它結合auto
關鍵字使用:
template <typename T1, typename T2>
auto Add(T1 a, T2 b) -> decltype(a + b)
{
return a + b;
}
auto function(args...) -> type
這種函式宣告時,以auto作為返回值型別,真實型別放後面透過->
連線的語法稱之為後置返回型別
。其中auto表示佔位符,表示後置返回型別提供的型別,這是C++11給auto新增的一種作用。這種用法也可以用於一般函式的定義。
auto foo() -> int
{
}