有下面這個情況:
template <class T1, class T2>
void ft (T1 &x, T2 &y)
{
...
?type? xpy = x+;
...
}
在這種情況下xpy應該是什麼類型呢?由於不知道ft()將如何使用,因此無法預知這一點。正確的類型可能是T1、T2或者其他類型。假如又出現了重載運算符,這會讓問題更加的複雜。
於是爲了解決這個問題,c++11新增了關鍵字 decltype。
我們可以這樣使用:
int x;
decltype(x) y;//y的類型和x類型一致
除了上述這樣寫,我們也可以這樣寫:
decltype(x+y) xpy;
xpy = x+y;
通過這個關鍵字,我們可以把前面的代碼修改成這樣:
template <class T1, class T2>
void ft(T1 x, T2 y)
{
...
decltype(x+y) xpy = x+y;
...
}
decltype比這些實例要複雜些。爲了確定類型,編譯器必須遍歷一個覈對表。假設有如下聲明:
decltype (expression) var;
1.如果expression是一個沒有用括號括起的標識符,則var的類型與該標識符類型相同,包括const等限定符
double x = 5.5;
double y = 7.9
double &rx = x;
const double *pd;
decltype(x) w; // w is type double
decltype (rx) u = y; // u is type double &
decltype(pd) v; // v is type const double *
2.如果expression是一個函數調用,則var的類型與函數的返回類型相同:
long indeed(int)
decltype (indeed(3)) m; // is type int
這裏並不會實際調用函數。編譯器通過查看函數的原型來獲悉返回類型,而無需實際調用函數。
3.加入expression是用括號括起來的標識符:
double xx = 4.4;
decltype((xx)) r2 = xx ; // r2 is double &
decltype(xx) w = xx; // w is double
括號並不會改變表達式的值和左值性。
4.如果前面都不滿足,則var的類型與expression類型相同:
int j = 3;
int &k = j;
int &n = j;
decltype (j+6)i1; // i1 type int
decltype (100L) i2; // i2 type long
decltype (k+n) i3; // i3 type int
雖然k和n都是引用,是表達式k+n不是引用。
如果需要多次聲明,可以結合使用typdef和decltype:
template <class T1, class T2>
void ft(T1 x, T2 y)
{
typedef decltype (x+y) xytype;
xytype xpy = x+y;
xytype arr[10];
xytype &rxy = arr[2]; // rxy a reference
}
還有一個問題是decltype沒有辦法解決的:
template <class T1, class T2>
?type? gt(T1 x, T2 y)
{
return x+y;
}
同樣無法預知x和y相加得到的類型。看起來我們還可以用decltype,但是很不幸,這個時候還沒有聲明x和y,它們不在作用域內。必須在聲明參數後使用decltype。爲此,c++新增了一種聲明和定義函數的語法。
double h(intx, float y);
可以用新增的語法編寫成這個樣子:
auto h(int x, float y) -> double;
這將返回類型移到了參數聲明後面。->double被稱爲後置返回類型(trailing return type)。 其中auto是一個佔位符,表示後置返回類型提供的類型。這是c++11的新增auto語法。這個語法也可以用於函數定義。
auto h (int x, float y) -> double
{/* function body*/};
通過結合使用這種語法和decltype,便可以給gt()指定返回類型。
template <class T1, class T2>
auto gt(T1x, T2 y) ->decltype(x+y)
{
return x+y;
}
現在,decltype在參數聲明後面,因此x和y位於作用域內,可以使用它們。