Rokiのチラ裏

学生による学習のログ

Variadic templateへのあらゆる操作その2

前回書いていないようなメタ関数を書いてみたので一応。
※追記 改善を施しライブラリ化した

// First
template<class...>
struct First;
template<class Head,class... Tail>
struct First<Head,Tail...>{
    typedef Head type;
};
template<class Head,class... Tail>
struct First<pack<Head,Tail...>>{
    typedef Head type;
};
template<class... Pack>
using First_t=typename First<Pack...>::type;

// Last
template<class...>
struct Last;
template<class Head,class... Tail>
struct Last<Head,Tail...>{
    typedef typename Last<Tail...>::type type;
};
template<class Head,class... Tail>
struct Last<pack<Head,Tail...>>{
    typedef typename Last<Tail...>::type type;
};
template<class Tail>
struct Last<Tail>{
    typedef Tail type;
};
template<class... Pack>
using Last_t=typename Last<Pack...>::type;

// Popfront
template<class...>
struct Popfront;
template<class Head,class... Tail>
struct Popfront<Head,Tail...>{
    typedef pack<Tail...> type;
};
template<class Head,class... Tail>
struct Popfront<pack<Head,Tail...>>{
    typedef pack<Tail...> type;
};
template<class... Pack>
using Popfront_t=typename Popfront<Pack...>::type;

// Popback
template<class...>
struct Popback;
template<class Head,class... Tail>
struct Popback<Head,Tail...>{
    typedef Concat_t<Head,typename Popback<Tail...>::type> type;
};
template<class Head,class... Tail>
struct Popback< pack<Head,Tail...> >{
    typedef Concat_t<Head,typename Popback<Tail...>::type> type;
};
template<class Tail>
struct Popback<Tail>{
    typedef pack<> type;
};
template<class... Pack>
using Popback_t=typename Popback<Pack...>::type;

// Reverse
template<class... Args>
struct Reverse{
    typedef Concat_t< Last_t<Args...>,typename Reverse< Popback_t<Args...> >::type > type;
};
template<class... Args>
struct Reverse<pack<Args...>>{
    typedef Concat_t< Last_t<Args...>,typename Reverse< Popback_t<Args...> >::type > type;
};
template<>
struct Reverse<pack<>>{
    typedef pack<> type;
};
template<class... Args>
using Reverse_t=typename Reverse<Args...>::type;

// PartialHead
template<std::size_t,class...>
struct PartialHead;
template<std::size_t N,class Head,class... Args>
struct PartialHead<N,Head,Args...>{
    typedef Concat_t<Head,typename PartialHead<N-1,Args...>::type> type;
};
template<std::size_t N,class Head,class... Args>
struct PartialHead<N,pack<Head,Args...>>{
    typedef Concat_t<Head,typename PartialHead<N-1,Args...>::type> type;
};
template<class Tail,class... Args>
struct PartialHead<1,Tail,Args...>{
    typedef Tail type;
};
template<std::size_t N,class... Pack>
using PartialHead_t=typename PartialHead<N,Pack...>::type;

// PartialTail
template<class... Arg>
struct Apply;
template<class Head,class... Tail>
struct Apply<Head,Tail...>{
    typedef Concat_t<Head,typename Apply<Tail...>::type> type;
};
template<class Tail>
struct Apply<Tail>{
    typedef Tail type;
};
template<>
struct Apply<>{
    typedef pack<> type;
};

template<std::size_t N,class Head,class... Tail>
struct PartialTail{
    typedef typename PartialTail<N-1,Tail...>::type type;
};
template<std::size_t N,class Head,class... Tail>
struct PartialTail<N,pack<Head,Tail...>>{
    typedef typename PartialTail<N-1,Tail...>::type type;
};
template<class Head,class... Tail>
struct PartialTail<0,Head,Tail...>{
    typedef Concat_t<Head,typename Apply<Tail...>::type> type;
};
template<std::size_t N,class... Args>
using PartialTail_t=typename PartialTail<N,Args...>::type;

// At
template<std::size_t index,class...>
struct At;
template<std::size_t index,class Head,class... Tail>
struct At<index,Head,Tail...>{
    typedef typename At<index-1,Tail...>::type type;
};
template<std::size_t index,class Head,class... Tail>
struct At<index,pack<Head,Tail...>>{
    typedef typename At<index-1,Tail...>::type type;
};
template<class Target,class... Tail>
struct At<0,Target,Tail...>{
    typedef Target type;
};
template<std::size_t index,class... Pack>
using At_t=typename At<index,Pack...>::type;

改善版

patialモノはまあまあ便利なのではないかと思う。

typedef pack<int,char,float,double,int> test_type;
PartialHead_t<3,test_type>; // int char float
PartialTail_t<3,test_type>; // float double int

型のサイズごとのクイックソートを実装しようかと目論んだが、面倒になってしまったので誰か適当にやっといて欲しい。

template<class...> struct Left{};
template<class...> struct Right{};

template<int,bool,class,class...>
struct QSort_Skip_Counter;
template<int N,class Pivot,class Head,class... Tail>
struct QSort_Skip_Counter<N,false,Pivot,Head,Tail...>{
    static constexpr int value=QSort_Skip_Counter<N+1,(sizeof(Head)<sizeof(Pivot)),Pivot,Tail...>::value;
};
template<int N,class Pivot,class Tail>
struct QSort_Skip_Counter<N,false,Pivot,Tail>{
    static constexpr int value=N-1;
};
template<std::size_t N,class Pivot,class... Tail>
struct QSort_Skip_Counter<N,true,Pivot,Tail...>{
    static constexpr int value=0;
};

template<bool,class,class,class...>
struct QSort_Skip_impl;
template<class Pivot,class Head,class... Tail>
struct QSort_Skip_impl<false,Pivot,Head,Tail...>{
    typedef typename QSort_Skip_impl<( sizeof(Head)<sizeof(Pivot) ),Pivot,Tail...>::type type;
    static constexpr std::size_t value=QSort_Skip_Counter<0,(sizeof(Head)<sizeof(Pivot)),Pivot,Tail... >::value;
};
template<class Pivot,class Head,class... Tail>
struct QSort_Skip_impl<true,Pivot,Head,Tail...>{
    typedef Head type;
    static constexpr std::size_t value=QSort_Skip_Counter<0,(sizeof(Head)<sizeof(Pivot)),Pivot,Tail... >::value;
};

template<class...>
struct QSort_Skip;
template<class Pivot,class Head,class... Tail>
struct QSort_Skip<Pivot,Right<Head,Tail...>>{
    typedef typename QSort_Skip_impl< (sizeof(Head)<sizeof(Pivot)),Pivot,Head,Tail... >::type type;
    static constexpr std::size_t value=QSort_Skip_impl< (sizeof(Head)<sizeof(Pivot)),Pivot,Head,Tail... >::value;
};
template<class Pivot,class Head,class... Tail>
struct QSort_Skip<Pivot,Left<Head,Tail...>>{
    typedef typename QSort_Skip_impl< (sizeof(Head)>sizeof(Pivot)),Pivot,Head,Tail... >::type type;
    static constexpr std::size_t value=QSort_Skip_impl< (sizeof(Head)>sizeof(Pivot)),Pivot,Head,Tail... >::value;
};

template<bool,class,class,class,std::size_t,std::size_t>
struct Swap_Apply;
template<class Args...,class L,class R,std::size_t L_index,std::size_t R_index>
struct Swap_Apply<false,pack<Args...>,L,R,L_index,R_index>{
    /*typedef left_pack;
   typedef right_pack;
   typedef All_pack;*/
    static constexpr bool condition=false;
};
template<class... Args,class L,class R>
struct Swap_Apply<true,pack<Args...>,L,R,L_index,R_index>{
private:
    typedef Concat_t<PartialHead_t<L_index-1,Args...>,L> left_pack_tmp;
    typedef Concat_t<PartialHead_t<R_index-1,Args...>,R> right_pack_tmp;
public:
    typedef Concat_t<left_pack_tmp,PartialHead_t<L_index,Args...>> left_pack;
    typedef Concat_t<left_pack_tmp,PartialTail_t<R_index,Args...>> right_pack;
    typedef Concat_t<left_pack,right_pack> All_pack;
};

template<class...>
struct QSort;
template<class Head,class... Tail>
struct QSort<pack<Head,Tail...>>{
private:
    typedef pack<Head,Tail...> All_t;
    typedef At_t<(sizeof...(Tail)+1)/2,Head,Tail...> pivot_type;
    typedef typename QSort_Skip<pivot_type,Right<Head,Tail...>>::type skiped_left;
    typedef typename QSort_Skip<pivot_type,Left<Head,Tail...>>::type skiped_right;
    static constexpr std::size_t skiped_left_value=QSort_Skip<pivot_type,Right<Head,Tail...>>::value;
    static constexpr std::size_t skiped_right_value=QSort_Skip<pivot_type,Left<Head,Tail...>>::value;
    
    typedef Swap_Apply<( skiped_left_value >= skip_righted_value ),All_t,skiped_left,skiped_right,skiped_left_value,skiped_right_value>::type type;
};
template<class... Pack>
using QSort_t=typename QSort<Pack...>::type;

template<class T>
struct type_index{
    explicit type_index()noexcept{std::cout<< boost::typeindex::type_id<T>().pretty_name() <<std::endl;}
};

恐らく愚直に実装しようとしているから面倒なのだと思うのだが、何か面倒でない方法はないだろうか。

※追記
一つに適用するものと、全てに適用するメタ関数は、それぞれタグごとに処理を切り替えられるよう、xxxerとして新たに定義した。

以下のように使える。

#include<srook/mpl/variadic_player.hpp>
#include<boost/type_index.hpp>
#include<cstdio>
#include<tuple>

int main()
{
    using namespace boost::typeindex;
    using namespace srook::mpl;
    using TestType=pack<int,int,int,int,char,char,char,char>;

    std::printf("%s\n%s\n%s\n%s\n",
            type_id< Transfer_t<std::tuple,Eraser_t<variadic_tag::Single,int,TestType>> >().pretty_name().c_str(),
            type_id< Transfer_t<std::tuple,Eraser_t<variadic_tag::All,int,TestType>> >().pretty_name().c_str(),
            type_id< Transfer_t<std::tuple,Replacer_t<variadic_tag::Single,int,char,TestType>> >().pretty_name().c_str(),
            type_id< Transfer_t<std::tuple,Replacer_t<variadic_tag::All,int,char,TestType>> >().pretty_name().c_str());
}
std::__1::tuple<int, int, int, char, char, char, char>
std::__1::tuple<char, char, char, char>
std::__1::tuple<char, int, int, int, char, char, char, char>
std::__1::tuple<char, char, char, char, char, char, char, char>