可变参函数模板
概述
可变参数模版(variadic templates)是C++11新增的最强大的特性之一,它对参数进行了高度泛化,它能表示0到任意个数、任意类型的参数。
格式
template <typename... T>
void fuc(T... args)
{
std::cout << sizeof...(args) << std::endl; //sizeof...可变参数量
}
可变参数包的若干展开方式
1、递归继承方式展开可变参数包
//code
namespace ParsesVariadicByInheritance
{
template<typename ...Args>
class xhVariadicTemplates;//主模板
template<>
class xhVariadicTemplates<>
{
public:
xhVariadicTemplates()
{
std::cout <<"type: "<<typeid(void).name() << std::endl;
}
};
template<typename Head, typename ... Tail>
class xhVariadicTemplates<Head, Tail ...> :private xhVariadicTemplates<Tail ...>
{
public:
xhVariadicTemplates(Head head, Tail ... tail) :xhVariadicTemplates<Tail ...>(tail ...)
{
std::cout << "type: "<<typeid(std::declval<Head>()).name() <<"\t value: "<< head << std::endl;
}
};
}
//test
int main()
{
ParsesVariadicByInheritance::xhVariadicTemplates<int, double, float,std::string> obj(12,12.12,12.12f,"xu");
return 0;
}
//output
type: void
type: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > value: xu
type: float value: 12.12
type: double value: 12.12
type: int value: 12
2、递归组合方式展开可变参数包
//code
namespace ParsesVariadicByComposition
{
template<typename ...Args>
class xhVariadicTemplates;//主模板
template<>
class xhVariadicTemplates<>
{
public:
xhVariadicTemplates()
{
std::cout << "type: " << typeid(void).name() << std::endl;
}
};
template<typename Head, typename ... Tail>
class xhVariadicTemplates<Head, Tail ...> //: private myclasst<Others...> //偏特化
{
public:
xhVariadicTemplates(Head head, Tail ...tail) :mHead(head), mTail(tail...) //, myclasst<Others...>(paro...)
{
std::cout << "type: " << typeid(std::declval<Head>()).name() << "\t value: " << head << std::endl;
}
Head mHead;
xhVariadicTemplates<Tail...> mTail; //组合关系
};
}
//test
int main()
{
ParsesVariadicByComposition::xhVariadicTemplates<int, double, float,std::string> obj(12,12.12,12.12f,"xu");
return 0;
}
//output
type: void
type: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > value: xu
type: float value: 12.12
type: double value: 12.12
type: int value: 12
3、通过tuple和递归调用展开参数包
//code
namespace ParsesVariadicByTuple
{
//实现思路:计数器从0开始,每处理一个参数,计数器+1,一直到把所有参数处理完。模板偏特化,作为递归调用结束;
//currentCount用于计数,从0开始,maxCount表示参数数量
template<int currentCount, int maxCount, typename...T>
class xhVariadicTemplates
{
public:
static void parsesFuc(const std::tuple<T...>& t)
{
std::cout << "type: " << typeid(std::get<currentCount>(t)).name() << "\t value: " << std::get<currentCount>(t) << std::endl;
xhVariadicTemplates<currentCount + 1, maxCount, T...>::parsesFuc(t); //递归调用
}
};
//特化版本,用于结束递归调用
template <int maxCount, typename...T>
class xhVariadicTemplates< maxCount, maxCount, T...>
{
public:
static void parsesFuc(const std::tuple<T...>& t) {}
};
template <typename...T>
void parsesFuc(const std::tuple<T...>& t) //可变参函数模板
{
xhVariadicTemplates<0, sizeof...(T), T...>::parsesFuc(t);
}
}
//test
int main()
{
using namespace std::literals::string_literals;
ParsesVariadicByTuple::parsesFuc(std::make_tuple(12, 12.12, 12.12f, "xu"s));
return 0;
}
//output
type: int value: 12
type: double value: 12.12
type: float value: 12.12
type: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > value: xu
4、通过逗号表达式展开参数包
逗号表达式在C++中有这样的特性:(A,B,C),则从左到右求值,最后C的(返回)值作为整个表达式的值。
//code
namespace ParsesVariadicByCommaExpression
{
template <typename T>
int printArg(T t)
{
std::cout << "type: " << typeid(t).name() << "\t value: " << t << std::endl;
return 0;
}
template <typename ...Args>
void parses(Args... args)
{
int array[] = { (printArg(args), 0)... };
}
}
//test
int main()
{
using namespace std::literals::string_literals;
ParsesVariadicByCommaExpression::parses(12, 12.12, 12.12f, "xu"s);
return 0;
}
//output
type: int value: 12
type: double value: 12.12
type: float value: 12.12
type: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > value: xu
原理:
通过初始化列表来初始化一个变长数组, { (printArg(args), 0)… }将会展开成((printarg(arg1), 0), (printarg(arg2), 0), (printarg(arg3), 0),…);
parses函数中的逗号表达式:(printArg(args), 0),先执行printArg(args)输出参数,再得到逗号表达式的结果0。最后生成一个元素值都为0的,长度为sizeof…(Args)的数组。