Item3 Understand decltype
来源:互联网 发布:项目管理流程软件 编辑:程序博客网 时间:2024/06/01 10:51
这个系列的文章来自于Effective Modern C++的读书笔记,我抽取了其中比较重要的,不容易理解的,平常我们开发过程中也不太在意的一些Item进行分析。
decltype
是用来推导变量的类型,但是不像auto和模板类型推导那样,存在很多类型推导规则,decltype
推导出来的类型和变量原来的类型一模一样,没有做任何改动。在C++11中decltype
结合auto
还可以完成函数返回值的类型推导。
template<typename Container,typename Index>auto AccessContainer(Container& c,Index i) -> decltype(c[i]) { return c[i];}
到了C++14的时候就可以省略掉后面的-> decltype(c[i])
了,变成下面的样子。
template<typename Container,typename Index>auto AccessContainer(Container& c,Index i) { return c[i];}
上面的这个例子是用来访问容器中某个位置的元素,也就是容器的operator[]
操作符返回的元素,按照容器的定义这个操作符应该返回的是一个引用,也就是说你可以像下面这样给某个位置赋值。
std::vector<int> d;AccessContainer(d,5) = 100;
但是很不幸,你会发现编译出错,原因则是罪魁祸首的,auto
,返回值遇到auto后,引用被忽略掉了,在Item1中的Case3
中详细解释了这个规则,为了让上面的的例子可以正常运行,可以做如下改动。
template<typename Container,typename Index>auto& AccessContainer(Container& c,Index i) { return c[i];}
返回的是一个auto&
,至于为什么可以参考Item1中的Case1,除次之外还可以用C++14的另外一种写法如下:
template<typename Container,typename Index>decltype(auto) AccessContainer(Container& c,Index i) { return c[i];}
通过decltype
保证返回变量的本来类型这一特性,保证不丢失CV
限制符,和引用等,因此在C++14中可以通过decltype
和auto
来声明变量,保证变量的类型和赋值的类型一模一样。
int ia = 10;const int& iia = ia;auto autoia = cw; //推导出的类型是int,引用和CV限制符都会忽略decltype(auto) deautoia = cw; //const int& 保证和cw的类型一模一样
上面的方案通过decltype
和auto
让返回值的类型变的完美,但是如果用户传入一个const的容器,将会导致编译出错。因为AccessContainer
的参数类型是非常量引用,为了让他可以接收常量和非常量,需要使用常量引用(神奇的常量引用)。
template<typename Container,typename Index>decltype(auto) AccessContainer(const Container& c,Index i) { return c[i];}
这带来的另外一个问题就是,c[i]
,返回的是常量引用,无法修改。好在C++11中引入了右值引用,它还有另外一个名字叫做通用引用,通过名字就可以知道这个引用很通用,它可以接收左值,右值还有带const的。
template<typename Container,typename Index>decltype(auto) AccessContainer(Container&& c,Index i) { return c[i];}
到此为止看似已经很完美了,可以接收任何类型的容器,返回值也和传入的类型一致,但是上述方案仍然有不足之处如果用户传入的是一个右值,通过移动语义传递给了AccessContainer
的参数c
,但是c本身其实是一个左值,如果在AccessContainer中需要把c
再次传递给其他的函数的话就不能再次利用右值的移动语义了,带来了不必要的拷贝开销。C++11中的完美转发使得上面的方案变得完美,它可以将参数原封不动的传递给其他的函数。
template<typename Container,typename Index>decltype(auto) AccessContainer(Container&& c,Index i) { return std::forward<Container>(c)[i];}
到此为止实现了一个完美的AccessContainer
,关于完美转发可以参考这篇文章C++0x里的完美转发到底是神马?
decltype
如此完美,从文章的开篇我就一直强调decltype
的好,它可以完美的得到目标变量的类型,但是在大多数人的眼中C++怎是那么的不完美,decltype
会打破这个定律吗? 当然没有,decltype
也有例外的时候。
int x = 0;decltype(x) //得到的是int类型decltype((x)) //得到的是int&类型
上面的变量x加了一个括号后就变成了一个引用类型了,根据官方如下:
The type denoted by decltype(e) is defined as follows: — if e is an unparenthesized id-expression or an unparenthesized class member access (5.2.5), decltype(e) is the type of the entity named by e. If there is no such entity, or if e names a set of overloaded functions, the program is ill-formed; — otherwise, if e is an xvalue, decltype(e) is T&&, where T is the type of e; — otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e; — otherwise, decltype(e) is the type of e.The operand of the decltype specifier is an unevaluated operand (Clause 5).[ Example:const int&& foo();int i;struct A { double x; };const A* a = new A();decltype(foo()) x1 = i; // type is const int&&decltype(i) x2; // type is intdecltype(a->x) x3; // type is doubledecltype((a->x)) x4 = x3; // type is const double&—end example ]
对于x
来说,没有括号括起来,所以符号第一条规则,类型就是x
本身,而(x)
不符号第一条,也不符合第二条,因为他是左值所以符合第三条,所有就是int&
。具体内容可以参考stackoverflow
哈哈,其实decltype
真的还好了,C++11中至今感觉坑比较少的一个特性吧。
- Item3 Understand decltype
- <Effective Mordern C++>笔记:Item 3:Understand decltype .
- 《Effective Modern C++》读书笔记(3) -- 明白decltype(understand decltype)
- decltype
- decltype
- decltype
- item3: 尽可能使用const
- Effective C++ Item3
- c++ decltype
- decltype() demo
- decltype() demo
- decltype类型
- decltype(表达式)
- c++ decltype
- C++ decltype
- 关键字decltype
- Item3: Use const whenever possible
- Understand inline
- 始终灼热的坚持.
- Java设计模式--工厂模式(简单工厂+工厂方法)
- 记一次web服务的调优
- 第五周 项目5-后缀表达式
- php微信支付
- Item3 Understand decltype
- 浅析JAVA中toString方法的作用
- hiho 1383 The Book List
- 先定一个小目标
- java连接SQL Server 2005数据库教程(手把手教程)
- SAP GUI740 PATCH10 下载
- HTML中>的含义
- 函数调用过程(详解)
- 十六进制转十进制