可変長テンプレートでunion
C++勉強ネタが続きます
templateを作って直和型もどきを作りたいときがあります。
これはすでにBoost Library
で実現されていて、boost::variant
として利用できます。
また、C++1z
では、これが標準に追加されます。
今回は、可変長テンプレートを使ってこれを実装してみたいと思い立ち書いてます。
boost::variant
はインデックス用の数字を保存しますが、今回は値だけを格納することにします。
とりあえず、データ構造はこんな感じでしょうか
U[3]
がU.nxt.nxt.nxt.v
になるみたいなイメージです
template <size_t N, class Head, class ...Tail> union U { Head v; U<N-1 ,Tail...> nxt; }; template <class Head,class ...Tail> union U<0,Head,Tail...> { Head v; };
これを初期化するクラスを作っておきます
template <class ...Args> class Union{ U<sizeof...(Args)-1,Args...> u; };
中身を取り出したいので、
auto v3 = get<3>(u);
みたいにかけるようにしたいですね
template <size_t N> struct _getter { template <size_t U_N, class U_Head, class... U_Tail> static auto get(const U<U_N,U_Head,U_Tail...>& u){ return _getter<N-1>::get(u.nxt); } }; template <> struct _getter<0>{ template <size_t U_N, class U_Head, class... U_Tail> static auto get(const U<U_N,U_Head,U_Tail...>& u){ return u.v; } }; template <size_t N, class...Args> auto get(const Union<Args...>& u){ return _getter<N>::get(u.u); }
うーん…
int main(){ union _u { char c; double d; int i; }; Union<char ,double ,int> uni; variant<char, double ,int> var; auto v0 = get<0>(uni); cout << sizeof(v0) << endl; // 1 cout << sizeof(_u) << endl; // 8 cout << sizeof(uni) << endl; // 8 cout << sizeof(var) << endl; // 16 }
unionと同サイズになることがわかりますね。
独自の型を実装していて、セレクタが不要な場合などに使えそう。