C++模板笔记
参考文章:https://juejin.cn/post/7078530622527897631
模板是C++的泛型编程机制,这种机制可以最大程度复用代码并且不会增加运行时开销
模板分为函数模板和类模板
函数模板
函数模板是对函数的参数进行泛型化,传递给模板函数的类型实参可以是类,也可以是整型值,还可以是模板名
比如:
// 参数是类型的情况
template<typename T>
T add_1(T a, T b)
{
return a+b;
}
// 参数是int值的情况
template<typename T, int N>
T add_2(T a, T b)
{
printf("N=%d\n", N);
return a+b;
}
// 参数是模板名的情况
template<template<class> class H, typename T>
H<T>& add_h(H<T> a)
{
return a;
}
函数模板的隐式实例化和显式实例化
显示实例化就是在使用函数模板时指定模板参数
隐式实例化是在使用函数模板时不指定模板参数,让编译器自动推导类型
例如:
add_1<int>(1, 2); // 显式指定了T为int,那就是显式实例化
add_1(1, 2); // 编译器会自动推导T为int,那就是隐式实例化
隐式实例化机制仅针对函数模板而言,类模板中是没有隐式实例化机制的。
类模板
类模板对类的参数进行泛型化,传递给模板类的类型实参可以是类,也可以是整型值
template
class TemplateClass
{
T a;
};
成员函数模板
成员函数也可以用template进行泛型化声明,与前面的函数模板一样。
模板参数可以指定默认值
看到这个地方的时候有个疑问,为什么模板有类型推导机制可以推导出模板的类参数,那为什么还要有默认值的机制?
看到这个例子就明白了:
template <typename T = int>
class DefClass {};
不是所有的模板参数都可以通过模板实参来推导出来。
默认值的指定需要从最右端开始,也就是说从左边开始第一个指定了默认值的参数后,后面的参数都需要指定默认值。
在实例化函数模板时,如果所有参数都有默认值,可以不加<>就可以全部使用默认值,但是对于类模板,必须指定一个空的参数列表<>才能实例化。
另外还要注意,模板默认值功能是从c++0x之后才有,用较老版本的g++编译时需要增加-std=c++0x
参数推导的优先级和默认值的优先级哪个更高
如果一个函数模板的参数既有默认值,并且在实例化时没有指定参数类型,会优先选择哪个类型(默认值还是推导出的类型)?
#include <stdio.h>
#include <typeinfo>
template<typename T1=float, typename T2=float>
void add_3(T1 a, T2 b)
{
printf("T1 is %s, T2 is %s\n", typeid(T1).name(), typeid(T2).name());
}
经过验证类型推导优先级高一些。
模板参数默认值也可以由前面已定义的typename或者值来得出当前参数的默认值
模板的特化
特化是指在类名或者函数名称后再加一个特定的类型指定,以单独处理需要特别化的情况
函数模板的特化
对于函数模板的特化只能是全特化,不允许偏特化
template<typename T1=float, typename T2=float>
void add_3(T1 a, T2 b)
{
printf("T1 is %s, T2 is %s\n", typeid(T1).name(), typeid(T2).name());
}
template<>
void add_3<double, double>(double a, double b)
{
printf("add_3<double, double>, a is %s, b is %s\n", typeid(a).name(), typeid(b).name());
}
add_3(1.1, 1.2); //add_3<double, double>, a is d, b is d //1.1推导为double,1.2推导为double,所以选择了特化版本的函数模板
add_3(1.1f, 1.2); //T1 is f, T2 is d //1.1f推导为float,1.2推导为double,所以选择了基础版本的函数模板
类模板的特化
全特化
template <>
class Data<char*, char*>
{};
偏特化
部分参数不变,部分参数特化
template <typename T1>
class Data<T1, char*>
{};
参数进一步限制
部分参数进行了限制,比如T*, T&, const T&, const T[], const T[100], const *T[]等
template <typename T1, typename T2>
class Data<T1*, T2*>
{};
优先级是全特化>偏特化>参数进一步限制。