模板支持将类型作为参数的程序设计方法,从而实现了对泛型程序设计的直接支持。模板提供了:
传递类型参数而不丢失信息的能力;
推迟的类型检查(在实例化时进行):有机会把来自不同上下文的信息编织在一起;
传递常量参数的能力:能进行编译时计算。
值作为实参
非类型或模板的模板参数称为值参数(value parameter),传递给他的实参称为值实参(value argument)。值参数的实参可以是:
整型常量表达式:字符串字面值不能作为模板实参(可转换为数组传入);
外部连接的对象或函数的指针或引用;
执行非重载成员的指针:像&X::of;
空指针。
template
class X{};
X x1; #错误,提示字符串常量不能作为参数
char szX2[] = "Success";
X X2; #正确,字符串指针可作为参数
template // 可以是整型,但不能是浮点数
class X2{};
X2 x3;
操作作为实参
传递函数对象,而非函数指针给模板参数,有明显优点:
类内定义的简单类成员函数适合内联,而函数指针内联需要编译器特别关注才行;
传递无数据成员的函数对象无运行时开销;
很多操作都能以单一对象的形式传递且无额外运行时开销。
// Compare定义为类型,而非函数指针bool(*cmp)(const Key&, const Key&),以增加通用性
template>
class XMap {
public:
explicit XMap(const Compare& c = {}) :cmp{ c } {}
private:
Compare cmp{};
};
// 正在表达式需要先命名,才能使用(使用decltype获取其类型)
auto xcmp = [](const string& x, const string& y) ;
XMapdecltype(xcmp)> c1{ xcmp };
XMap c2; // 使用默认比较函数
模板作为实参
将一个模板声明为模板参数,必须指定其所需的实参。只有类模板可以作为模板实参。
template class C>
class Xrefd {
C mems;
C refs;
};
template using XVect = vector;
Xrefd xr; //??直接使用vector不行,必须using别名后使用
可变参数模板
可变参数模板和普通模板的语义是一样的,只是声明可变参数模板时需要在typename或class后面带上省略号“...”:
声明一个参数包T... args,这个参数包中可以包含0到任意个模板参数;
sizeof...(T) 可以用来获知参数包中打包了几个参数。
template
std::unique_ptr make_unique(TParam&&... params){
return unique_ptr(new T(forward(params)...));
}
通过递归函数可展开参数包,需要提供一个参数包展开的函数和一个递归终止函数:
template
T fSum(T first, TRs... rest) {
return first + fSum(rest...);
}
template
T fSum(T first) { // 终止函数,要求至少一个参数(若允许0个参数,在定义成0个参数)
return first;
}
此外也可借助逗号实现自动展开:
void fComma(TRs... args) {
//int tmp[] = { (CommaUt(args), 0) ... };
int tmp[] = { (cout
}
可变参数类模板展开
可通过类展开,实现编译时计算:
template
structFSize{ // 不能带模板类型
enum { Value = FSize::Value + FSize::Value };
};
template
struct FSize{ // 需要带模板类型
enum { Value = sizeof(TLast) };
};
cout ::Value
借助std::integral_constant(value为值,value_type为值类型,type为自身)可方便地实现编译时计算:
template
struct MyFac:integral_constant::value>{};
template
struct MyFac:integral_constant{};
领取专属 10元无门槛券
私享最新 技术干货