decltype 总结
第一个值得说明的问题是,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