與模板參數推導和auto推導同樣,decltype的結果大多數狀況下是正常的,可是也有少部分狀況是反直覺的。ios
給定一個name或者expression,decltype會告訴你它的類型。c++
咱們先從正常狀況開始:express
const int i = 0; // decltype(i) is const int bool f(const Widget& w); // decltype(w) is const Widget& // decltype(f) is bool(const Widget&) struct Point { int x, y; // decltype(Point::x) is int }; // decltype(Point::y) is int Widget w; // decltype(w) is Widget if (f(w)) … // decltype(f(w)) is bool template<typename T> // simplified version of std::vector class vector { public: … T& operator[](std::size_t index); … }; vector<int> v; // decltype(v) is vector<int> … if (v[0] == 0) … // decltype(v[0]) is int&
很直觀,沒有例外狀況。 注意:decltype與auto不一樣,不會消除const和引用。函數
好比咱們須要聲明一個函數模板,函數的返回值類型依賴函數參數的類型。在C++11中,常見的例子是返回一個container對應索引的值:ui
template <typename Container, typename Index> // works, but requires refinement auto authAndAccess(Container &c, Index i) -> decltype(c[i]) { return c[i]; }
注意:這裏的auto跟類型推導沒有任何關係,它只是代表了這裏使用了C++11的trailing return type
.code
在C++11中只容許單語句的lambda表達式被推導,在C++14中之中行爲被拓展到全部lambda和全部函數,包括多語句。在C++14中,上述代碼咱們能夠簡寫爲:索引
template<typename Container, typename Index> // C++14; not quite correct auto authAndAccess(Container& c, Index i) { return c[i]; // return type deduced from c[i] }
注意:這裏的auto就跟類型推導有關係了。 在前面講auto推導規則的文章中提到過,auto做用在函數返回值時,使用的是模板參數推導規則,這裏就會出現問題:operator []
咱們但願它返回引用,可是使用auto使用模板參數推導規則時,引用會被忽略,因此下面的代碼會報錯:ci
template <typename Container, typename Index> auto authAndAccess(Container &c, Index i) { return c[i]; } std::vector<int> v{1,2,3,4,5}; authAndAccess(v,2) = 10; // error: expression is not assignable
可是使用auto -> decltype()
則不會報錯,由於這裏auto不表明參數參數推導:get
template <typename Container, typename Index> auto authAndAccess(Container &c, Index i) -> decltype(c[i]) { return c[i]; } std::vector<int> v{1,2,3,4,5}; authAndAccess(v,2) = 10;
因此,要想讓authAndAccess在使用auto的狀況下返回引用,在C++14中,咱們可使用decltype(auto):it
template <typename Container, typename Index> decltype(auto) authAndAccess(Container &c, Index i) { return c[i]; } std::vector<int> v{1,2,3,4,5}; authAndAccess(v,2) = 10;
decltype(auto)中的auto表明返回值須要被自動推導,decltype表明使用decltype來推導返回值類型。
decltype(auto)不只能夠聲明函數返回值,還能夠聲明變量:
Widget w; const Widget& cw = w; // auto type deduction : myWidget1's type is Widget decltype(auto) myWidget2 = cw; // decltype type deduction : myWidget2's type is const Widget&
decltype的規則能夠看官網:decltype specifier,概況下能夠分爲兩大類:
decltype ( entity )
: 若是entity是一個不被括號包圍的標識符、類訪問表達式,那麼decltype ( entity )
與entity類型一致。decltype ( expression )
: 若是expression是一個表達式,計算結果爲類型T,那麼:
注意第一點中強調了entity是一個不被括號包圍的標識符。由於當一個標識符被括號包圍時,它就是一個左值表達式了,對應上面第二大點的第二小點。好比說int x = 0;
,x是一個標識符,因此decltype(x)
的結果爲int。可是(x)就是一個左值表達式,decltype((x))
的結果就是int&。因此下面的用法是不一樣的:
decltype(auto) f1() {
int x = 0;
…
return x; // decltype(x) is int, so f1 returns int
}
decltype(auto) f2() {
int x = 0;
…
return (x); // decltype((x)) is int&, so f2 returns int&
}
官網的例子能很好的概況decltype最多見的用法:
#include <iostream> struct A { double x; }; const A* a; decltype(a->x) y; // type of y is double (declared type) decltype((a->x)) z = y; // type of z is const double& (lvalue expression) template<typename T, typename U> auto add(T t, U u) -> decltype(t + u) // return type depends on template parameters // return type can be deduced since C++14 { return t + u; } int main() { int i = 33; decltype(i) j = i * 2; std::cout << "i = " << i << ", " << "j = " << j << '\n'; auto f = [](int a, int b) -> int { return a * b; }; decltype(f) g = f; // the type of a lambda function is unique and unnamed i = f(2, 2); j = g(3, 3); std::cout << "i = " << i << ", " << "j = " << j << '\n'; }
(完)
朋友們能夠關注下個人公衆號,得到最及時的更新: