模板类型推导
前言
类型推导使得程序员从冗杂的类型名拼写上解放出来,本篇文章将详细介绍模型类型推导的规则。
模板类型推导的规则
考虑如下函数模版:
1 | |
在编译期间,编译器使用expr进行两个类型的推导:T和ParamType。其中,ParamType通常包含一些修饰,从而通常与T是不同的类型。T的类型推导不仅取决于expr的类型,也被ParamType决定,可以将其分为三种情况:
ParamType是一个指针或引用,但不是通用引用ParamType是一个通用引用ParamType既不是指针也不是引用
下面分别介绍三种情况下的类型推导规则
情况一:ParamType是一个指针或引用,但不是通用引用
在该情况下,类型推导按照如下规则进行:
- 如果
expr的类型是一个引用,忽略引用部分 expr的类型与ParamType进行模式匹配决定T
对于如下模板示例:
1 | |
则类型推导结果如下:
1 | |
从上述结果中可以看出,const对象作为实参传递给T&形参时,const会被保留为T的一部分。
如果param是一个指针,对应的情况与引用基本一致:
1 | |
情况二:ParamType是一个通用引用
该情况的形式如下:
1 | |
对应的类型推导规则有以下几点:
- 如果
expr是左值,T和ParamType都会被推导为左值引用。 - 如果
expr是右值,使用情况一的推导规则(T保留const属性和基本类型,param是右值引用)
下面给出对应的示例:
1 | |
情况三:ParamType既不是指针也不是引用
该情况下通过传值的方式处理:
1 | |
对应如下规则:
- 如果
expr的类型是一个引用,忽略这个引用部分 - 如果忽略
expr的引用性之后,expr是一个const,那么再忽略const。如果是volatile,也忽略volatile。
下面给出对应的示例:
1 | |
该情况下,param是传入对象的拷贝,不影响传入对象。
一个例外情况是传入的是指向常量的常量指针,此时指针指向数据的常量性会被保留,而指针本身的常量性会被忽略:
1 | |
数组实参
我们知道数组在某些上下文中会退化为指向它的第一个元素的指针,给出如下示例:
1 | |
在该示例中,name的类型为const char[13],而ptrToName的类型为const char*,但编译器允许数组退化为指针。
将数组作为实参传递给模版:
1 | |
有没有办法让T推导为数组,而不是指针呢?答案是使用传引用模板:
1 | |
此时T会被推导为真正的数组const char[13],形参类型为const char (&)char[13]。
我们可以根据这一性质创建一个模板函数推导数组的大小:
1 | |
函数实参
函数类型也会退化为函数指针,对于数组类型的推导可以应用到函数类型退化到函数指针上来:
1 | |
参考
模板类型推导
https://delta0406.github.io/2025/06/14/技术/语言/CPP/模板类型推导/