対数オーダー再起で構築されるtupleのギミックを大雑把に実装した
(追記)こっちも読め。こっちのがいい
再帰深度を抑えたtuple的コンテナの構築 - ここは匣
(追記終わり)
調査環境はVS2013のみ
たぶんO(log N)で動く
コード中のstd::tupleはtype_listの代わりに使った。std::tupleを入れると実は対数オーダーにならないんじゃないか疑惑があるがその時はちゃんとtype_listを実装して差し替えればよい
template<class T,class ID> struct Data { template<class U> Data(U&&arg) :data(std::forward<U>(arg)) {} using data_type = T; T data; }; template<class ...T> class make_tuple_Elem { //tuple<integral_constant<size_t,N>...>が返るメタ関数 //理由は普通のindex_sequenceだとコンパイラがバグるから using Seq = index::make_tuple_t<sizeof...(T)>; //ZIP template<class...T,class...N> static auto trans(std::tuple<T...>, std::tuple<N...>) ->std::tuple<Data<T, N>...>; public: using type = decltype(trans(std::declval<std::tuple<T...>>(), Seq{})); }; template<class> struct tuple_impl{}; template<class ...T> struct tuple_impl<std::tuple<T...>> :T... { template<class ...R> tuple_impl(R&&...args) :T(std::forward<R>(args))... {} template<size_t N> auto get() ->typename typename utility::type_at<N, T...>::type::data_type& { return static_cast<utility::type_at_t<N, T...>&>(*this).data; } }; template<class ...T> struct tuple :tuple_impl<typename make_tuple_Elem<T...>::type> { using base = tuple_impl<typename make_tuple_Elem<T...>::type>; template<class ...R> tuple(R&&...args) :base(std::forward<R>(args)...) {} };
//main tuple<char, int, std::string> c('A', 42, "String"); std::cout << c.get<2>();//String c.get<2>() = "TXT.TXT"; std::cout << c.get<2>();//TXT.TXT
ギミックの解説
- tupleの時 メタ関数make_tuple_Elemはstd::tuple< Data< A,0>,Data< B,1>,Data< C,2>>を作る。この時使われるindex_tupleはO(log N)で実装できる
- tuple_implはstd::tuple< Data< A,0>,Data< B,1>,Data< C,2>>を受け取りData< A,0>,Data< B,1>,Data< C,2>を多重継承する
- 要素を取り出すときはget< N>を用いる(実際使うときはstd::get関数のようにラッパする)
type_atを用いてN番目の継承している型を取り出しキャストすることでデータを取り出す
この時型が被っていてもData< int,0> , Data< int,5>のようになるので衝突することはない
この時使われるtype_atはO(log N)で実装できる
http://txt-txt.hateblo.jp/entry/2014/05/16/174537
const とかmoveとかはいろいろやれば何とかなるだろう。たぶん
operator=とかいろいろなコンストラクタとかもなんか頑張れば行けるだろう。たぶん