问题
给定 一个变长模板,取出其中第n个元素的类型 (tuple_element, get(tuple)...)
template <size_t Idx, class ...Types>
using get_nth_type = ...;
static_assert(std::is_same<int, get_nth_type<2, float, double, int>>::value, "");
解决,参考libcxx 的 include/__tuple
namespace indexer {
template <size_t Idx, class Type> struct indexed {
using type = Type;
};
template <class ..._Types> struct __tuple_types {};
template <size_t ..._Idxs> struct __tuple_indices {};
template <class _Types, class _Indexes> struct indexer;
template <class ...Types, size_t ..._Idx>
struct indexer<__tuple_types<Types...>, __tuple_indices<_Idx...>>
: indexed<Types, Idx>...
{};
template <size_t Idx, class Tp>
indexed<Idx, Tp> at_index(indexed<Idx, Tp> const &);
template <size_t Idx, class ...Types>
using get_nth_type = typename decltype(
at_index(indexer<
__tuple_types<Types...>,
typename __make_tuple_indices<sizeof...(Types)>::type
>{})
)::type;
} /* namespace indexer */
主要看indexer的偏特化,当模版参数为__tuple_types 和 __tuple_indices的时候,其继承自indexed<Types, Idx>...
举例来说该模板会如下展开
using tuple_types_a = __tuple_types<int, float, double>;
using tuple_indices_a = __tuple_indices<0, 1, 2>;
indexer<tuple_types_a, tuple_indices_a>
: indexed<0, int>, indexed<1, float>, indexed<2, double>
{};
在调用 at_index<n>的时候,如果形参类型为 indexer<__tuple_types<Types...>, __tuple_indices<Idx...>>,模板会匹配到indexed<n, typen>;
于是通过decltype函数的返回值,就会得到indexed<n, ...>这个类型,萃取其type即可。
关于 __make_tuple_indices<size_t N>其type为__tuple_indices<0, 1, 2, ..., N>。
下面说下__make_tuple_indices的实现
首先是基本的defination
template <size_t...> struct __tuple_indices {}; //接收形如 1,2,3...的模板参数
template <class _IdxType, _IdxType... _Values>
struct __integer_sequence {
template <template <class _OIdxType, _OIdxType...> class _ToIndexSeq, class _ToIndexType>
using __convert = _ToIndexTypeSeq<_ToIndexType, _Values...>;
template <size_t _Sp>
using __to_tuple_indices = __tuple_indices<(_Values + _Sp)...>;
};
using int_seq = __interger_sequence<size_t, 0, 1, 2, 3>;
using my_tuple_indices = typename int_seq::template __to_tuple_indices<10>; //now my_tuple_indices is __tuple_indices<10, 11, 12, 13>;
下面开始骚操作, 将一个integer_sequence展开,输入1,2,3 输出1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24。
template <typename _Tp, size_t ...Extra> struct __repeat;
template <typename _Tp, _Tp... _Np, size_t... _Extra>
struct __repeat<__integer_sequence<_Tp, _Np...>, _Extra> {
typedef __integer_sequence<_Tp,
_Np...,
(sizeof...(_Np) + _Np)...,
(2*sizeof...(_Np) + _Np)...,
(3*sizeof...(_Np) + _Np)...,
(4*sizeof...(_Np) + _Np)...,
(5*sizeof...(_Np) + _Np)...,
(6*sizeof...(_Np) + _Np)...,
(7*sizeof...(_Np) + _Np)...,
_Extra...> type;
};
using int_seq = __integer_sequence<size_t, 1, 2>;
using repeated = typename __repeat<int_seq>::type;
//now repeated is __integer_sequence<size_t,
// 1, 2,
// 3, 4,
// 5, 6,
// 7, 8,
// 9, 10,
// 11, 12,
// 13, 14,
// 15, 16>;
//
有了__repeat 元函数,__make_tuple_indices<N> 构造如下
__repeat<__integer_sequence<0,1,2,...,N/8-1>, N - N%8, N - N%8 +1 ,..., N>
上面不是一个合法的模版类型,加一层是其合法如下
template<size_t _Np> struct __parity;
template<size_t _Np> struct __make : __parity<_Np % 8>::template __pmake<_Np> {};
template<> struct __make<0> { typedef __integer_sequence<size_t> type; };
template<> struct __make<1> { typedef __integer_sequence<size_t, 0> type; };
template<> struct __make<2> { typedef __integer_sequence<size_t, 0, 1> type; };
template<> struct __make<3> { typedef __integer_sequence<size_t, 0, 1, 2> type; };
template<> struct __make<4> { typedef __integer_sequence<size_t, 0, 1, 2, 3> type; };
template<> struct __make<5> { typedef __integer_sequence<size_t, 0, 1, 2, 3, 4> type; };
template<> struct __make<6> { typedef __integer_sequence<size_t, 0, 1, 2, 3, 4, 5> type; };
template<> struct __make<7> { typedef __integer_sequence<size_t, 0, 1, 2, 3, 4, 5, 6> type; };
template<> struct __parity<0> { template<size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type> {}; };
template<> struct __parity<1> { template <size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 1> {}; };
template<> struct __parity<2> { template <size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 2, _Np - 1> {}; };
template<> struct __parity<3> { template <size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<4> { template <size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
template<> struct __parity<5> { template <size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 5, _Np - 4, _Np - 3, _Np - 2,_Np - 1> {}; };
template<> struct __parity<6> { template <size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np -2, _Np - 1> {}; };
template<> struct __parity<7> { template <size_t _Np> struct __pmake : __repeat<typename __make<_Np / 8>::type, _Np - 7, _Np - 6, _Np - 5, _Np - 4, _Np - 3, _Np - 2, _Np - 1> {}; };
网友评论