1. decltype关键字
decltype被称作类型说明符,它的作用是选择并返回操作数的数据类型。
例如
Test2函数的返回值是std::initializer_list类型
std::initializer_list<int> Test2()
{
return { 1,2,3 };
}
我们使用一致化初始列表
decltype(Test2()) Arr1 = { 1,2,3 };
可以运行,所以decltype关键字得到了Test2返回值的类型
2.更多的常规例子
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&
3.C11
在C++11中,这个关键字的主要用途是你声明了一个函数模板,该函数模板的返回值依赖于形参类型。
template<typename Container, typename Index> // works, but
auto authAndAccess(Container& c, Index i) // requires
-> decltype(c[i]) // refinement
{
return c[i];
}
注意
①上述代码中的auto并不代表自动类型推导,他仅代表一种语法
表示正在使用C++11尾置返回类型的语法特性
②尾部返回类型的优点是,函数的参数可以用于指定返回类型
4. C14
C++11允许对单语句的lambda表达式进行类型推导。在C++14中,拓展为所有lambda和所有函数,包括多个语句(甚至多个返回,提供所有产出相同的推导类型)。这就意味着,在C++14中我们可以忽略尾置返回类型,单单只留下auto
template<typename Container, typename Index> // C++14;
auto authAndAccess(Container& c, Index i) // not quite
{ // correct
return c[i]; // return type deduced from c[i]
}
①使用这种形式,那么auto确实会发生类型推导了
②这就表明 编译器将从函数的实现中推断出函数的返回类型
问题来了 编译器根据auto来进行推断
根据前面的条款,那么会推断成什么呢?
只会返回它的value, 也就是说是一个右值
std::deque<int> d;
…
authAndAccess(d, 5) = 10; // authenticate user, return d[5],
// then assign 10 to it;
// this won't compile!
那么如何改变这种呢?
template<typename Container, typename Index> // C++14; works,
decltype(auto) // but still
authAndAccess(Container& c, Index i) // requires
{ // refinement
authenticateUser();
return c[i];
}
5. decltype(auto)
decltype(auto)的使用不仅仅局限于函数的返回值,也可以用于声明变量
Widget w;
const Widget& cw = w;
auto myWidget1 = cw; // auto type deduction:
// myWidget1's type is Widget
decltype(auto) myWidget2 = cw; // decltype type deduction:
// myWidget2's type is
// const Widget&
6.再次分析
authAndAccess(Container& c, Index i)
客户可能仅仅想得到一份拷贝
std::deque<std::string> makeStringDeque(); // factory function
// make copy of 5th element of deque returned
// from makeStringDeque
auto s = authAndAccess(makeStringDeque(), 5);
该模板无法为c传入一个右值,因为c是一个引用,所以上述模板仍需要改进
template<typename Container, typename Index> // c is now a
decltype(auto) authAndAccess(Container&& c, // universal
Index i); // reference
现在c是一个通用引用了,可以为c传入右值或者左值
c现在是一个通用引用。在这个模板中,我们不知道正在操作的容器的类型,这也意味着我们对它使用的索引对象的类型同样无知。为了使得它满足各种各样的情况,我们需要再次修改代码:
template<typename Container, typename Index> // final
decltype(auto) // C++14
authAndAccess(Container&& c, Index i) // version
{
authenticateUser();
return std::forward<Container>(c)[i];
}
C++11可以这么写
template<typename Container, typename Index> // final
auto // C++11
authAndAccess(Container&& c, Index i) // version
-> decltype(std::forward<Container>(c)[i])
{
authenticateUser();
return std::forward<Container>(c)[i];
}
7.decltype(x) 和 decltype((x))
左值会被decltype推导成引用
int x = 0;
(x);
(x)会被当做成一个左值
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&
}
f2返回了一个对局部变量的引用,这对C系程序员可谓是灾难了QAQ
8.注意
第二点
int nNum1 = 10;
decltype(auto)d = nNum1 = 20;
左值表达式 所以d被推导成int &
nNum1不是表达式 ,而是一个变量名称
decltype(auto)d = nNum1;
d是int