第一個值得說明的問題是,operator[] on a container of objects of type T typically returns a T&.[]操作符用於儲存T類型對象的容器時通常返回T&,具體問題需要具體分析,decltype一個[]操作符,返回類型依賴存儲它的容器。vector<bool>就比較特殊。
template<typename Container, typename Index> // works, but auto authAndAccess(Container& c, Index i) // requires -> decltype(c[i]) // refinement { authenticateUser(); return c[i]; }
這段C++11代碼有效,但是存在一下問題,我們使用位置返回類型,並且使用c和i,對於其他函數如果無法獲取c和i,那麼無法使用decltype。這個方法可以完善。
template<typename Container, typename Index> // C++14; auto authAndAccess(Container& c, Index i) // not quite { // correct authenticateUser(); return c[i]; // return type deduced from c[i] }
這段C++14代碼不正確,從條款一,二可知,auto會把左值引用識別為去掉引用的部分,這裡其實我們需要返回左值引用。
template<typename Container, typename Index> // C++14; works, decltype(auto) // but still authAndAccess(Container& c, Index i) // requires { // refinement authenticateUser(); return c[i]; }
decltype(auto)終於搞定了,我們不在需要尾置返回類型,並且類型識別為左值引用。但是這個方法仍然需要完善。
因為我們仍然需要面臨一個問題,這個模板無法使用右值。所以無法傳入一個臨時的容器對象。我們需要支持類似下面的操作
std::deque<std::string> makeStringDeque(); // factory function // make copy of 5th element of deque returned // from makeStringDeque auto s = authAndAccess(makeStringDeque(), 5);
那麼需要引入新詞語,全球通引用和完美轉發,今年C++標准委員會開大會,決定把universal references正式更名為forwarding references(轉發引用),轉發引用一般用與完美轉發,需要深入了解一下std::forward和std::move兩個函數,以及右值引用和左值引用區別,這個後續條款有講,並且我也打算專門為右值引用寫一片文章。
template<typename Container, typename Index> // final decltype(auto) // C++14 authAndAccess(Container&& c, Index i) // version { authenticateUser(); return std::forward<Container>(c)[i]; }
這樣一切都搞定了。
最後需要注意一些小問題,比如
int x; decltype((x)) //type is int&
更詳細的細節:
1) If the argument is either the unparenthesised name of an object/function,sion (object.member
or pointer->
or is a member access expresmember
), then the decltype specifies the declared type of the entity specified by this expression.
2) If the argument is any other expression of type T
, then
a) if the value category of expression is xvalue, then the decltype specifies T&&
b) if the value category of expression is lvalue, then the decltype specifies T&
c) otherwise, decltype specifies T
除了括號非常特殊以外,decltype((變量,只有名字的表達式))的類型總會是個引用。如果是一個簡單的表達式(只有名字這種objec.member也算簡單),那麼decltype就是返回它的類型。
對於其他任何比較復雜的表達式,遵循2),
這裡給出一個英文的連接,供參考什麼是左值,右值,x值
http://en.cppreference.com/w/cpp/language/value_category