在前面我们学习了模板的基础用法【c++】 模板初阶-CSDN博客初步认识了函数模板和类模板,接下来让我们看看模板还有哪些进阶的应用。
之前我们用到的模板全都使用了类型参数
类型参数:表示某种数据类型(如 int、double、自定义类等)。
非类型参数:表示常量值(如整数、指针、引用等)。
这样模板的每一个类型参数都要由我们传入的数据类型在实例化的时候由编译器确定。在一些特定的情况,会用到常量;如我们需要一个定长的数组时。控制数组长度的类型时确定的(如size_t),这样我们只设置一个类型参数就可以了。
namespace xian
{
//定义一个模板类型的定长数组
template<typename T,size_t N>
class array
{
public:
T& operator[](size_t n)
{
return _array[n];
}
const T& operator[](size_t n) const
{
return _array[n];
}
size_t size()
{
return _size;
}
bool empty()
{
return 0 == _size;
}
private:
T _array[N];
size_t _size;
};
}注意:非类型模板参数只能用于整型;不支持浮点数,类对象和字符串。c++20之后可以支持double作非类型模板参数。
非类型模板参数支持缺省值:
template<size_t N = 10>
class Stack
{
private:
int a[N];
int _top;
};
int main()
{
//Stack s0; 这种写法要c++20以后才支持
Stack<> s1; //我们还是用这种写法的好
}
// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{
return left < right;
}
int main()
{
cout << Less(1, 2) << endl;
Date d2(2022, 7, 8);
Date d1(2022, 7, 7);
cout << Less(d1, d2) << endl;//可以正常判断
Date* p2 = &d2;
Date* p1 = &d1;
cout << Less(p1, p2) << endl; //会直接比较指针
return 0;
}
根据地址比较大小,而地址的申请时随机的,这样结果是不能确定的。对于这种有特殊情况的可以使用模板的特化,把特殊情况单独拿出来处理。
// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{
return left < right;
}
// 对Less函数模板进行特化
template<>
bool Less<Date*>(Date* left, Date* right)
{
return *left < *right;
}
int main()
{
cout << Less(1, 2) << endl;
Date d2(2022, 7, 8);
Date d1(2022, 7, 7);
cout << Less(d1, d2) << endl;//可以正常判断
Date* p2 = &d2;
Date* p1 = &d1;
cout << Less(p1, p2) << endl; //会直接比较指针
return 0;
}有特化后的类之后,会直接使用特化后的类。


总结:
大多数时候,我们都选择简单的方法直接把特殊的情况函数直接给出而不是使用特化。使用特化容易出错,一般不要使用函数模板特化
全特化就是将模板参数全部特化
//全特化
template<class T1, class T2>
class Data
{
public:
Data() { cout << "Data<T1, T2>" << endl; }
private:
T1 _d1;
T2 _d2;
};
template<>
class Data<int, char>
{
public:
Data() { cout << "Data<int, char>" << endl; }
private:
int _d1;
char _d2;
};
void TestVector()
{
Data<int, int> d1;
Data<int, char> d2;
}偏特化是对模板参数部分特化,不仅仅是列出部分模板参数的具体类型,也可能是对原始模板作一些限制。
偏特化一共有两种表现方式:
template<class T1, class T2>
class Data
{
public:
Data() { cout << "Data<T1, T2>" << endl; }
private:
T1 _d1;
T2 _d2;
};
//部分特化
template<class T1>
class Data<T1, char>
{
public:
Data() { cout << "Data<int, char>" << endl; }
private:
T1 _d1;
char _d2;
};
void TestVector()
{
Data<int, int> d1;
Data<int, char> d2;
}
template <class T1>
class Data<T1, int>
{
public:
Data() { cout << "Data<T1, int>" << endl; }
private:
T1 _d1;
int _d2;
};template<class T1, class T2>
class Data
{
public:
Data() { cout << "Data<T1, T2>" << endl; }
private:
T1 _d1;
T2 _d2;
};
//限制传入的数据类型为指针
template<class T1, class T2>
class Data<T1*,T2*>
{
public:
Data() { cout << "Data<T1, T2>" << endl; }
private:
T1 _d1;
T2 _d2;
};
//限制传入的数据类型为引用
template<class T1, class T2>
class Data<T1&, T2&>
{
public:
Data() { cout << "Data<T1, T2>" << endl; }
private:
T1 _d1;
T2 _d2;
};