在学习元编程过程中,需要用到模板递归,函数模板和类模板的递归方式略有差别,主要是由于二者特化语法的差别导致的。通过一些例子整理了函数模板和类模板的特化语法和差异。
// 函数模板不支持偏特化,不能通过模板设置递归终止,可以用constexpr if终止递归
template <typename T, int n>
void printTuple(const T& t) {
if constexpr (n > 1) {
printTuple<T, n - 1>(t);
}
cout << get<n-1>(t) << endl;
}
// 不允许偏特化函数模板,编译错误
//template
//void printTuple (const T& t) {
//}
// 给n提供默认值,简化调用
template <typename T, int n=tuple_size<T>::value>
void printTuple2(const T& t) {
if constexpr (n > 1) {
printTuple<T, n - 1>(t);
}
cout << get<n - 1>(t) << endl;
}
int main()
{
tuple<int, double, const char*, string> tp{1, 2.0, "hi", "boy"};
using atuple = tuple<int, double, const char*, string>;
printTuple<atuple, tuple_size<atuple>::value>(tp);
printTuple2<atuple>(tp);
}
// 利用函数模板完全特化实现递归展开
template<int N>
int factorial() {
return N * factorial<N-1>();
}
template<>
int factorial<0>() {
return 1;
}
int main() {
std::cout << factorial<5>() << std::endl; // 输出:120
return 0;
}
类模板可以实现多个参数的模板偏特化,偏特化类型参数、值参数都支持。
// 通过类模板特化实现递归终止
// 也可以使用constexpr if实现终止逻辑,这样就不用特化终止条件的类模板class TuplePrint
// 这里的n也可以提供默认值tuple_size::value
template <typename T, int n>
class TuplePrint
{
public:
TuplePrint(const T& t) {
//if constexpr (n > 1) {
TuplePrint<T, n - 1> tp{ t };
//}
cout << get<n - 1>(t) << endl;
}
};
template <typename T>
class TuplePrint<T, 0>
{
public:
TuplePrint(const T& t) {}
};
int main()
{
tuple<int, double, const char*, string> tp{1, 2.0, "hi", "boy"};
using atuple = tuple<int, double, const char*, string>;
TuplePrint<atuple, tuple_size<atuple>::value> tpr{tp};
}
// 使用constexpr if实现终止逻辑,这样就不用特化终止条件的类模板class TuplePrint
// 这里的n也可以提供默认值tuple_size::value
template <typename T, int n>
class TuplePrint
{
public:
TuplePrint(const T& t) {
if constexpr (n > 1) {
TuplePrint<T, n - 1> tp{ t };
}
cout << get<n - 1>(t) << endl;
}
};
int main()
{
tuple<int, double, const char*, string> tp{1, 2.0, "hi", "boy"};
using atuple = tuple<int, double, const char*, string>;
TuplePrint<atuple, tuple_size<atuple>::value> tpr{tp};
}
// 工具方法,打印3个参数,简化类实现
void print(auto a, auto b, auto n) {
cout << endl;
cout << "a: " << typeid(a).name() << endl;
cout << "b: " << typeid(b).name() << endl;
cout << "n: " << n << endl;
}
template <typename Ta, typename Tb, int n>
class oneclass
{
public:
oneclass(const Ta& a, const Tb& b) {
print(a, b, n);
}
};
template <typename Ta, typename Tb>
class oneclass<Ta, Tb, 10>
{
public:
oneclass(const Ta& a, const Tb& b) {
print(a, b, 10);
cout << "specialization for 10 :)" << endl;
}
};
template <typename Ta, int n>
class oneclass<Ta, int, n>
{
public:
oneclass(const Ta& a, const int& b) {
print(a, b, n);
cout << "specialization for Tb :)" << endl;
}
};
template <typename Tb, int n>
class oneclass<int, Tb, n>
{
public:
oneclass(const int& a, const Tb& b) {
print(a, b, n);
cout << "specialization for the 1st type Ta :)" << endl;
}
};
int main()
{
oneclass<double, const char*, 2> oc1 { 1.0, "hi" };
oneclass<double, const char*, 10> oc2 { 2.0, "hi" };
oneclass<double, int, 11> oc3 { 1.0, 3 };
oneclass<int, const char*, 11> oc4 { 4, "hi" };
}
运行结果:
// oneclass oc1 { 1.0, "hi" }; 输出
a: double
b: char const * __ptr64
n: 2
// oneclass oc2 { 2.0, "hi" }; 输出
a: double
b: char const * __ptr64
n: 10
specialization for 10 :)
// oneclass oc3 { 1.0, 3 }; 输出
a: double
b: int
n: 11
specialization for Tb :)
// oneclass oc4 { 4, "hi" }; 输出
a: int
b: char const * __ptr64
n: 11
specialization for the 1st type Ta :)
template <typename Ta, typename Tb>
void printSum(Ta a, Tb b) {
cout << "general: sum=" << a + b << endl;
}
// 函数模板不支持偏特化,error
//template
//void printSum(const Ta& a, const int& b) {
// cout << "T&int: sum=" << a + b << endl;
//}
template <>
void printSum<int, int>(int a, int b) {
cout << "int: sum=" << a + b << endl;
}
template <typename T>
void printSum(T a, T b) {
cout << "T: sum=" << a + b << endl;
}
int main()
{
printSum(1.0f, 1); // general: sum=2, printSum
printSum(1.0, 2.0); // T: sum=3, printSum
printSum(1, 3); // T: sum=4, printSum,这里有限调用版本,除非像下面显示调用的函数,
printSum<int, int>(1, 4); // int: sum=5, printSum
printSum<double, int>(1, 5); // general: sum=6, printSum
}
// 类模板的定义和特化
template<模板参数列表,包括类型参数、非类型参数>
class ClassName { ... }
// 完全特化
template<>
class ClassName<特化模板参数列表,包括具体类型、非类型参数的具体值> { ... }
// 部分特化,偏特化
template<未特化的模板参数列表,包括类型、非类型参数>
class ClassName<未特化的类型或变量名, 特化的具体类型名或具体值> { ... }
// 函数模板的定义和特化
template<模板参数列表,包括类型参数、非类型参数>
returnType func { ... }
// 完全特化函数模板
template<>
returnType func<特化模板参数列表,包括具体类型、非类型参数的具体值> { ... }