?
这个IndexOf的实现比较简单,在展开参数包的过程中看是否匹配到特化的IndexOf,如果匹配上则终止递归将之前的value累加起来得到目标类型的索引位置,否则将value加1,如果所有的类型中都没有对应的类型则返回-1;
?
编译期根据索引位置查找类型:
?
?
template
struct At;
?
template
struct At
{
? ? using type = typename At::type;
};
?
template
struct At<0, T, Types...>
{
? ? using type = T;
};
? ? 用法:
using T = At<1, int, double, char>::type;
? ? cout << typeid(T).name() << endl; //输出double
?
At的实现比较简单,只要在展开参数包的过程中,不断的将索引递减至0时为止即可获取对应索引位置的类型。接下来看看如何在编译期遍历类型。
?
?
template
void printarg()
{
? ? cout << typeid(T).name() << endl;
}
?
template
void for_each()?
{
? ? std::initializer_list
{(printarg(), 0)...};
}
用法:for_each();//将输出int double
?
这里for_each的实现是通过初始化列表和逗号表达式来遍历可变模板参数的。
?
可以看到,借助可变模板参数和type_traits以及模板偏特化和递归等方式我们可以实现一些有用的编译期算法,这些算法为我们编写应用层级别的代码奠定了基础,后面模板元
编程的具体应用中将会用到这些元函数。
?
C++11提供的tuple让我们编写模版元程序变得更灵活了,在一定程度上增强了C++的泛型
编程能力,下面来看看tuple如何应用于元程序中的。
?
5.tuple与模版元
?
C++11的tuple本身就是一个可变模板参数组成的元函数,它的原型如下:
?
template
class tuple;
?
tuple在模版元编程中的一个应用场景是将可变模板参数保存起来,因为可变模板参数不能直接作为变量保存起来,需要借助tuple保存起来,保存之后再在需要的时候通过一些手段将tuple又转换为可变模板参数,这个过程有点类似于化学中的“氧化还原反应”。看看下面的例子中,可变模板参数和tuple是如何相互转换的:
?
?
//定义整形序列
template
struct IndexSeq{};
?
//生成整形序列
template
struct MakeIndexes : MakeIndexes{};
?
template
struct MakeIndexes<0, indexes...>{
? ? typedef IndexSeq type;
};
?
template
void printargs(Args... args){
? ? //先将可变模板参数保存到tuple中
? ? print_helper(typename MakeIndexes::type(), std::make_tuple(args...));
}
?
template
void print_helper(IndexSeq
, std::tuple&& tup){
? ? //再将tuple转换为可变模板参数,将参数还原回来,再调用print
? ? print(std::get(tup)...);?
}
template
void print(T t)
{
? ? cout << t << endl;
}
?
template
void print(T t, Args... args)
{
? ? print(t);
? ? print(args...);
}
?
用法:printargs(1, 2.5, “test”); //将输出1 2.5 test
?
上面的例子print实际上是输出可变模板参数的内容,具体做法是先将可变模板参数保存到tuple中,然后再通过元函