功能
实现编译期的整数序列,如下例make_index_sequence<3>()会使fun函数的模板参数: int... N 推演为:0,1,2序列 :
#include <iostream>
#include <tuple>
using namespace std;
template<int... N>
decltype(auto) fun(index_sequence<N...> is) {
return make_tuple(N...);
}
int main() {
auto t = fun(make_index_sequence<3>());
cout << std::get<0>(t) << endl;
cout << std::get<1>(t) << endl;
cout << std::get<2>(t) << endl;
return 0;
}
实现分析
傻瓜式实现
即是生成一个可变的编译期整数序列,实际上目的就是要生成如下类的对象:
template<int...N>
struct index_sequence {};
定义出上面的index_sequence后,其实就可以使用了,仍利用fun函数,调用方式为:
auto t = fun(index_sequence<0,1,2>());
实际上就是一个空类,因为我们的目的只是模板的可变参数(英文直译应叫模板参数包),并生成一个递增的整数序列,这种实现实际什么都不需要做。
更好的实现
分析,c++14的实现的make_index_sequence模板只需指定一个模板参数 “N”,就会自动生成整数序列:0 - N-1,从接口来看:
make_index_sequence<4> 可以实现为index_sequence的子类或,一个函数,并返回index_sequence<0,1,2...>对象。
继承方式实现
因c++14已定义index_sequence,为避免符号冲突,使用index_seq代替。
template<int... N>
struct index_seq{};
template<int N, int ...M>
struct make_index_seq: public make_index_seq<N - 1, N -1, M...> {
};
template<int ...M>
struct make_index_seq<0, M...> : public index_seq<M...> {
};
实现的原理是,当给定一个整数N,如3,定义make_index_seq<3>() 对象时,模板可变参数M,由空逐渐推导为序列0,1,2。
即make_index_seq<3> 时,M 为空。
make_index_seq<3-1,3-1, M...>时,M 为3-1 = 2
make_index_seq<2-1,2-1,M...>时,M为2-1=1,2 即序列(1,2)
make_index_seq<1-1,1-1,M...>时,M为1-1 = 0, 1,2即序列(0,1,2)
make_index_seq<0,M...>时, M为(0,1,2)此时,make_index_seq<3>实际继承自index_seq<0,1,2>
这样就生成了编译期的整数序列。
对于使用函数方式还不知道是否可行,整体思路的代码如下:
template<int... M>
void make_index_seq_impl(std::true_type t) {
}
template<int N, int... M>
void make_index_seq_impl(std::false_type t) {
(N < 1) ? (make_index_seq_impl<M...>(std::true_type())) : (make_index_seq_impl<N-1, N-1, M...>(std::false_type()));
}
此种写法是不可以的,会导编译器编译时,模板的无穷递归。