EMCPP条款3:理解decltype
一般用法
最基础的用法不赘述。
返回值型别尾序语法(trailing return type syntax)
| 1 | template<typename Container, type Index> | 
在C++14中,上面代码中的 -> decltype(c[i])其实可以省略,编译器会自动推导 c[i]作为函数返回值类型。但是,大多数含有型别 T 的对象的容器的 operator[] 会返回 T&。条款1解释说,模板型别推导过程中,初始化表达的引用性会被忽略,所以下面代码就不会通过编译:
| 1 | std::deque<int> d; | 
返回类型会被推导为 int,而且是个右值。
可以使用 decltype(auto) 克服上述问题:
| 1 | template<typename Container, type Index> | 
这里函数返回值为 T&,推导过程采用了 decltype 的规则。
在变量声明上,也可以使用这种形式:
| 1 | Widget w; | 
authAndAccess 函数只能接收左值,但有时候可能需要传入一个右值,这时候可以使用万能引用:
| 1 | template<typename Container, type Index> | 
对未知型别的对象采用按值传递有着诸多风险:非必要的复制操作带来的性能隐患、对象截切 (slicing) 问题带来的行为异常(参见条款41),还有同行的嘲笑等。但是在容器下标这个特定问题上,遵循标准库中给出的下标值示例(例如 std::string、std::vector 和 std::deque 的 operator[])应该是合理的,所以这里坚持使用了按值传递。不过,我们需要更新该模板的实现,以使它与条款25所教导我们的内容相符:对万能引用要应用 std::forward:
| 1 | template<typename Container, type Index> | 
猎奇一下,如果 decltype 接收的仅有一个名字,那么行为保持不变,如果接收的是一个更复杂的表达式,它会得出左值引用。对于 int x = 0;,decltype(x) 的结果是 int,但 decltype((x)) 的结果是 int&。
要点速记:
- 绝大多数情况下,decltype会得出变量或表达式的型别而不作任何修改。
- 对于型别为 T的左值表达式,除非该表达式仅有一个名字,decltype总是得出型别T&。
- C++14支持 decltype(auto),和auto一样,它会从其初始化表达式出发来推导型别,但是它的型别推导使用的是decltype的规则 。