跳转至

条款1: 理解模板型别推导

有如下模板伪代码:

template<typename T>
void f(ParamType param);

f(expr);

T的型别推导,不仅仅依赖实参的型别,还依赖ParamType的形式。具体有:

  • ParamType 具有指针或引用型别(非万能引用)。
  • ParamType 是一个万能引用。
  • ParamType 既非指针也非引用。

情况1 ParamType是指针或引用

即如下(可能的):

template<typename T>
void f(T& param);

型别推导会这样做:

  1. 若expr具有引用型别,先将引用部分忽略。

  2. 尔后,对expr的型别和ParamType的型别执行模式匹配,来决定T的型别。

情况2 ParamType是万能引用

即如下:

template<typename T>
void f(T&& param);

注意,形参声明方式写作T&&

如果expr是左值,T和ParamType都会被推导为左值引用。

如果expr是右值,则使用情况1中的规则。

情况3 ParamType既非指针也非引用

即如下:

template<typename T>
void f(T param);

导出规则为:

  • 若expr具有引用型别,则忽略其引用部分。
  • 之后,若expr是个const对象,也忽略之。

Note

这里说的const对象是指顶层const,即如果是const char *const,那么会推导成const char *

数组实参

由于数组到指针的退化规则的存在,如果模板函数如:

template<typename T>
void f(T param);

那么将一个数组(比如 const char name[] = "diwen")传递给它时,T会被推导成 const char *

可以将形参声明成数组的引用,方法是将模板改成:

template<typename T>
void f(T& param);

T将推导出实际的数组型别,包含数组的尺寸。

利用这一能力,可以创造一个模板,用来推导出数组含有的元素个数:

template<typename T, std::size_t N>
constexpr std::size_t arraySize(T (&)[N]) noexcept
{
    return N;
}