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
的规则 。