Understand template type deduction
auto
是建立在模板类型推导的基础上的,这项条款能帮助理解auto
基于的模板类型推导。
我们将基于这个模板进行讨论:
1 | template<typename T> |
在编译期间,编译器使用expr
进行两个类型推导:一个是针对T
的,另一个是针对ParamType
的。这两个类型通常是不同的,因为ParamType
包含一些修饰,比如const
和引用修饰符。在这种情况下,ParamType
是const T&
。
T
的类型推导不仅取决于expr
的类型,也取决于ParamType
的类型。这里有三种情况:
第一种情况: ParamType是引用或者指针, 但不是通用引用
规则是:
- 如果 expr 的类型是引用, 则忽略引用部分.
- 然后将 expr 的类型与 ParamType 进行模式匹配以确定 T.
1 | template<typename T> |
如果我们将f
的形参类型T&
改为const T&
,情况有所变化,cx
和rx
的const
ness依然被遵守,但是因为假设param
是reference-to-const
,const
不再被推导为T
的一部分:
1 | template<typename T> |
如果param
是一个指针(或者指向const
的指针)而不是引用,情况本质上也一样:
1 | template<typename T> |
第二种情况: ParamType是通用引用
规则是:
- 如果 expr 是左值,则 T 和 ParamType 都被推导为左值引用.
- 如果 expr 是右值,则适用第一种情况规则.
1 | template<typename T> |
当通用引用被使用时,类型推导会区分左值实参和右值实参。
第三种情况: ParamType既不是指针也不是引用
在这种情况下, 参数以传值(pass-by-value)的方式处理。无论传递什么,param
都会成为它的一份拷贝——一个完整的新对象。
规则是:
- 如果 expr\ 的类型是引用, 则忽略引用部分。
- 在忽略 expr 的引用性之后, 也忽略任何 const 和 volatile。
1 | template<typename T> |
即使cx
和rx
表示const
值,param
也不是const
。param
是一个完全独立于cx
和rx
的对象。
数组和函数参数的衰减
当我们将数组名称作为参数传递给函数时,它实际上会衰减为指向数组中第一个元素的指针。
1 | template<typename T> |
但是如果添加对数组的引用, 就可以推断出数组类型。
1 | template<typename T> |
不只是数组会退化为指针,函数类型也会退化为一个函数指针。
1 | void someFunc(int, double); //someFunc是一个函数, |
重点
- 在模板类型推导期间, 作为引用的参数被视为非引用, 即它们的引用性会被忽略。
- 在推导通用引用参数的类型时, 左值参数得到特殊处理。
- 在推导按值传递参数的类型时, const和volatile参数被视为非const和非volatile。
- 在模板类型推导期间, 数组或函数名的参数会衰退为指针, 除非它们被用于初始化引用。