Variadic Templateの(僕が今更ながら新しく知った)使い方

知った事など

  • 継承させる
struct Base1{};
struct Base2{};

// すべての型引数を継承
template<typename... Args>
struct Derived : Args...
{
   int a;
};

int main(){ Derived<Base1,Base2> a; }
  • mapして包含する(直接保持は無理)
struct Base1{};
struct Base2{};

template<typename... Ts>
struct holder
{ };

template<typename T>
struct Map
{ };

// 
template<typename... Args>
struct Derived
{
    // 保持
    typedef holder< Args... > hold_;
    
    // ERROR
    //typedef Map<Args...> type;
    
    // Args...をMapにmap
    // そのままは持てないのでラップする
    typedef holder< Map<Args>... > type;
};

int main(){ Derived<Base1,Base2> a;  }
  • mapして継承させる
struct Base1{};
struct Base2{};

template<typename T>
struct Map
{   };

// 継承
tempalte<typename... Args>
struct Derived : Map<Args>...
{
   
};

int main(){ Derived<Base1,Base2> a; }
  • もちろん複数のVaridic templateでも可
struct Base1{};
struct Base2{};

template<int N,typename T>
struct Map
{   };

// 継承
tempalte<int...Ns, typename... Args>
struct Derived : Map<Ns,Args>...
{
   
};

int main(){ Derived<1,2,Base1,Base2> a; }
  • 継承させた値(value)を扱う
// Argsの一部
struct Base1{ int value_; };

// Argsの一部
struct Base2{ int value_; };

// 継承
tempalte<typename... Args>
struct Derived : Args...
{
   template<typename T>
   auto get(T& t)
   { return t.value; }
};

int main()
{
   Derived<Base1,Base2> a();
   a.get<Base1>(); //Base1.value_
}

通常であれば、valueはBase1::valueとBase2::valueの2つあって区別できないのですが
get関数内でthisを継承元にキャストすることで、Base1の持つ変数、関数を直接操作することが可能になっています
(多重継承の場合は使えるのかな?)

本題

と言う事で、Map<N,T>を適応しつつ複数の型を継承することで
面白い事ができるようです

template<int N,typename T>
struct Map
{   T value_;   };

// 継承
tempalte<int... Ns, typename... Args>
struct Derived : Map<N,Args>...
{
   tempalte<int N>
   auto get()
   { return get_<N>(*this); }

   // 今回this(Derived型)はMap<1,int>,Map<2,double>,Map<3,char>を継承する
   // するとget_<1>のようにして数字を与えthisを引数にとると
   // どのMap<1,T>のT(即ちint)をthisの継承一覧から推論してくれる

   template<int N, typename T>
   static auto get_(Map<N,T>& t)
   { return t.value; }
};

int main()
{
   Derived<1,2,3,int,double,char> a();
   a.get<1>(); // return int
   a.get<2>(); // return double
   a.get<3>(); // return char
}

おもしろいですね
「Map<T,N>のどちらか一方が判明しているのなら、もう一方を推論できる」
のような挙動をしています
上のコードではgetメンバ関数で第1型引数だけを指定してあげることで、
Map<N,T>の第2型引数であるTを推論しています
とてもおもしろいです。私ははじめて知りました

tuple

面白半分でtupleを実装してみました
数字を自動生成してはいるものの、
いわゆるO(n)オーダーというナンセンスな実装です
http://melpon.org/wandbox/permlink/lTybRjzNIs0iNcSt