美文网首页
indexed type

indexed type

作者: Danpier | 来源:发表于2018-09-28 11:02 被阅读0次

问题

给定 一个变长模板,取出其中第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> {}; };

相关文章

网友评论

      本文标题:indexed type

      本文链接:https://www.haomeiwen.com/subject/uzaloftx.html