目录
面向对象编程(OOP)和泛型编程都能处理在编写程序时不知类型的情况,不同之处在于:OOP能处理类型在程序运行之前都未知的情况:而在泛型编程中,在编译时就能获知类型了
1. 定义模板
1.1. 函数模板
背景:比如我们需要来比较不同数据类型的两个值,并指出第一个值与第二个值的大小关系,如果此时只定义只比较一种参数类型的函数,略显麻烦。
此时引出了函数模板,此时就不用为每个类型定义一个新的函数了。
比如:
template<typename T>
int compare(const T& v1, const T& v2)
{
if (v1 < v2)return -1;
if (v2 < v1)return 1;
return 0;
}
模版定义:以关键字template开始,后跟一个模板参数列表,这是一个逗号分隔的一个或多个模板参数的列表,用小于号(<)和大于号(>)包围起来。
实例化函数模板
当我们调用一个函数模版时,编译器通常根据函数传入的实参来推断模板实参
例如,
cout << compare(1, 0) << endl;//T为int
实参为int型,编译器会将模板实参推断为int,并将它绑定到模板参数T
- 编译器用推断出的模板参数来为我们实例化,这些编译器生成的版本通常被称为模板的实例
模板类型参数
在模板参数列表中,使用关键字typename
或class
后面跟着一个标识符来定义模板类型参数。例如:
template<typename T>
void print(T value) {
std::cout << value << std::endl;
}
在上面的例子中,T
是一个模板类型参数,它表示一个不特定的数据类型。在函数体内,我们可以像使用任何其他类型一样使用T
。
- 返回类型和参数类型相同的模板示例:
template<typename T>
T identity(T value) {
return value;
}
在上面的例子
identity
是一个模板函数,它接受一个参数value
,类型为T
,并返回相同类型的值。无论传入什么类型的参数,该函数都会返回相同类型的值。
使用该模板函数的示例代码如下:
int main() {
int intValue = identity(42); // 返回 int 类型的值 42
double doubleValue = identity(3.14); // 返回 double 类型的值 3.14
std::string stringValue = identity("Hello"); // 返回 std::string 类型的值 "Hello"
return 0;
}
在上述示例中,
identity
函数根据传入的参数类型进行实例化,并返回相同类型的值。模板类型参数前必须使用关键字
class
或typename
,这是为了指示编译器该参数是一个类型参数。选择使用哪个关键字主要是个人偏好,但在C++标准中,更常见的做法是使用关键字 typename 来表示类型参数
非类型模板参数
非类型模板参数(Non-type Template Parameters):非类型模板参数允许我们在模板中使用常量值作为参数。它们用于在模板定义中指定一个常量值,而不是一个数据类型。非类型模板参数可以是整数、枚举、指针或引用类型。在模板参数列表中,我们使用一个特定的类型来定义非类型模板参数。例如:
template<int N>
int multiplyByN(int value) {
return value * N;
}
在上面的例子中,
N
是一个非类型模板参数,它表示一个整数常量值。在函数体内,我们可以将N
用作常量值来执行相应的计算。
- 非类型模版参数使用示例:
模版定义了两个非类型的参数。第一个模板参数表示第一个数组的长度,第二个模版参数表示第二个数组的长度:
template<unsigned N,unsigned M>
int compare(const char(&p1)[N], const char(&p2)[M])
//由于数组不能拷贝,所以定义为数组的引用
{
return strcmp(p1, p2);
}
当我们这样调用时:
compare("hi","mom");
编译器会使用字面常量的大小来代替N和M,从而实例化模版:
int compare(const char (&p1)[3],const char (&p2)[4])
- 一个非类型参数可以是一个整型,或者是一个指向对象或函数类型的指针或(左值)引用
- 绑定到非类型整型参数的实参必须是一个常量表达式
- 在模版定义内,模版非类型参数是一个常量值。在需要常量表达式的地方,可以使用非类型参数。例如指定数组大小
inline 和 constexpr的函数模版
函数模版可以声明为inline或constexpr的,如同非模版函数一样。inline或constexpr说明符放在模版参数列表之后,返回类型之前:
//正确:inline说明符跟在模版参数列表之后
template <typename T> inline T min(const T&,const T&);
//错误:inline 说明符的位置不正确
inline template<typename T> T min(const T&,const T&);
编写类型无关的代码
- 将参数设定为