一、可变参函数模板
二、可变参类模板
C++ 11 中引入了 可变参模板 (Variadic Template): 允许模板中含有 0 个到 任意个 模板参数。
一、可变参函数模板
(1) 可变参函数模板的基本写法
- T为可变参类型,是0到n个不同的类型
- args为可变形参,是对应的不同类型的参数
template<typename... T>
void VarFunc(T... args)
{
cout << sizeof...(T) << endl;
}
int main()
{
VarFunc(1, 0.5, 'a', "abc");
return 0;
}
(2) 递归函数展开参数包
- 将可变参函数模板的入参拆成 【一个形参,一包可变形参】
- 重载函数,作为递归终止函数,作为可变形参为空时调用的函数
// 递归终止函数
void VarFunc2()
{
cout << "end" << endl;
}
// 可变参函数模板
template<typename T, typename... U>
void VarFunc2(const T& t, const U&... args)
{
cout << t << endl;
VarFunc2(args...);
}
int main()
{
VarFunc2(1, 0.5, 'a', "abc");
return 0;
}
二、可变参类模板
(1) 递归继承方式展开参数包
// 泛化可变参类模板
template<typename... args>
class VarClass {};
// 全特化可变参类模板基类
template<>
class VarClass<>
{
public:
VarClass()
{
cout << "VarClass<>(), this = " << this << endl;
}
};
// 偏特化可变参类模板
template<typename val, typename... args>
class VarClass<val, args...> : private VarClass<args...>
{
public:
VarClass(val v, args... vs) : m_i(v), VarClass<args...>(vs...)
{
cout << "VarClass<val, args...>, this = " << this << endl;
cout << v << endl;
}
val m_i;
};
int main()
{
VarClass<int, double, string> v(1, 2.5, "abc");
return 0;
}
输出结果:

- 从输出结果可以看出,实例化的对象的首地址是一致的,属于继承关系,继承顺序为:
→ 继承于
VarClass<int, double, string> → VarClass<double, string> → 继承于 → VarClass<string> → VarClass<>
在实例化 VarClass<int, double, string> v(1, 2.5, "abc") 时,编译器相当于生成了以下的类:
// 泛化可变参类模板
template<typename... args>
class VarClass {};
// 全特化可变参类模板基类
template<>
class VarClass<>
{
public:
VarClass()
{
cout << "VarClass<>(), this = " << this << endl;
}
};
template<>
class VarClass<string> : private VarClass<>
{
public:
VarClass(string val) : m_val(val), VarClass<>()
{
cout << "VarClass<string> : " << m_val << endl;
}
string m_val;
};
template<>
class VarClass<double, string> : private VarClass<string>
{
public:
VarClass(double val, string arg1) : m_val(val), VarClass<string>(arg1)
{
cout << "VarClass<double, string>() : " << m_val << endl;
}
double m_val;
};
template<>
class VarClass<int, double, string> : private VarClass<double, string>
{
public:
VarClass(int val, double arg1, string arg2) : m_val(val), VarClass<double, string>(arg1, arg2)
{
cout << "VarClass<int, double, string>() : " << m_val << endl;
}
int m_val;
};
(2) 递归组合方式展开方式展开参数包
组合关系:类与类之间的关系,其中一个类包含另一个类的对象。
// 组合关系
class B
{
// todo...
};
class A
{
public:
B b; // A 中包含B对象
};
通过递归组合方式展开参数包:
template<typename... Args>
class VarClass{};
template<typename Val, typename... Args>
class VarClass<Val, Args...>
{
public:
VarClass(Val val, Args... args) : m_val(val), m_args(args...)
{
cout << "VarClass<Val, Args...>(), this : " << this << endl;
cout << m_val << endl;
}
Val m_val;
VarClass<Args...> m_args;
};
int main()
{
VarClass<int, double, string> var(1, 2.5, "hello");
return 0;
}
输出结果:

- 通过输出结果,可以看出实例化的对象的地址是不一致的,属于组合关系,组合顺序为:
→ 包含对象
VarClass<int, double, string> → VarClass<double, string> → VarClass<string> → VarString<>
实际上在实例化 VarClass<int, double, string> 时,编译器生成了以下几个类:
template<typename... Args>
class VarClass{};
template<>
class VarClass<string>
{
public:
VarClass(string val) : m_val(val)
{
cout << "VarClass<string>() : " << m_val << endl;
}
string m_val;
VarClass<> m_args;
};
template<>
class VarClass<double, string>
{
public:
VarClass(double val, string arg1) : m_val(val), m_args(arg1)
{
cout << "VarClass<double, string>() : " << m_val << endl;
}
double m_val;
VarClass<string> m_args;
};
template<>
class VarClass<int, double, string>
{
public:
VarClass(int val, double arg1, string arg2) : m_val(val) , m_args(arg1, arg2)
{
cout << "VarClass<int, double, string>() : " << m_val << endl;
}
int m_val;
VarClass<double, string> m_args;
};
(3) 通过 tuple 和递归调用方式展开参数包
tuple (元组):各种类型元素的组合
#include <iostream>
#include <tuple>
using namespace std;
int main()
{
tuple<int, char, string> t(1, 'a', "hello");
cout << get<0>(t) << endl;
cout << get<1>(t) << endl;
cout << get<2>(t) << endl;
return 0;
}
实现思路:计数器从0开始,每处理一个参数,计数器+1;直到把所有参数处理完成。最后使用一个模板偏特化,作为递归调用结束
// count从0开始统计, maxcount 表示参数数量
template<int count, int maxcount, typename... T>
class MyTuple
{
public:
static void TupleCount(const tuple<T...>& t)
{
cout << "value = " << get<count>(t) << endl;
MyTuple<count + 1, maxcount, T...>::TupleCount(t);
}
};
// 特化版本,结束递归调用
template<int maxcount, typename... T>
class MyTuple<maxcount, maxcount, T...>
{
public:
static void TupleCount(const tuple<T...>& t){}
};
template<typename... T>
void TupleFunc(const tuple<T...>& mytuple)
{
MyTuple<0, sizeof...(T), T...>::TupleCount(mytuple) ;
}
int main()
{
tuple<int, char, string> mytuple(1, 'a', "hello");
TupleFunc(mytuple);
return 0;
}
网友评论