理解 decltype关键字

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值