boost::recursive_variant_はプレースホルダーで、boost::make_recursive_variant(_over)がそれを実際のvariantの型に置換する。Boost.Multi-indexといっしょに使おうとしたら、話は若干面倒になるかもしれない。
multimapのかわりにmulti_index_containerを使う例を考える。ここではstd::pairを使用しているが、Emulating standard containers with multi_index_containerの通りにしたほうが良いかもしれない。
再帰的なvariantに素直に入れようとすると下記のようになるだろうか。もちろん、うまくいかない。
Key Extractorの指定において、メンバポインタを使用しているのが問題であることは一目瞭然だ。さすがにそこまでboost::recursive_variant_の置き換えが及ばない(いや、がんばって特殊化すれば、実装することは可能だろうけれど)。
解決するためにboost::multi_index::member_offsetを用いる方法を思いつくだろう。std::pair<std::string, T>について、Tがどのような型でも&std::pair<std::string, T>::firstが一定であろうことを利用する。しかし、これもまた、うまくいかない。
うまくいかない理由は、boost::recursive_variant_の置き換えの実装上の理由にある。任意のクラスについて、クラスの全てのテンプレート引数が型である場合にのみ置き換えの対象になる。つまり、型だけでなくsize_tを引数に取るboost::multi_index::member_offsetは置き換えの対象外となる。size_t自体ではなく、boost::mpl::size_tを引数に取るmember_offsetを作れば問題は解決できるが、そもそもメンバー変数のオフセットなんか取りたくはない。
シンプルにstd::pairの(一般化すればtuple用の)Key Extractorを定義するのが良いと思う。
すっきりした。
multimapのかわりにmulti_index_containerを使う例を考える。ここではstd::pairを使用しているが、Emulating standard containers with multi_index_containerの通りにしたほうが良いかもしれない。
typedef double value_type; typedef boost::multi_index_container< std::pair<std::string, value_type>, boost::multi_index::indexed_by< boost::multi_index::ordered_non_unique< boost::multi_index::member< std::pair<std::string, value_type>, std::string, &std::pair<std::string, value_type>::first > >, boost::multi_index::random_access<> > > container_type; container_type c; c.insert(c.end(), std::make_pair("foo", 42));
再帰的なvariantに素直に入れようとすると下記のようになるだろうか。もちろん、うまくいかない。
typedef boost::make_recursive_variant< boost::blank, double, std::string, boost::multi_index_container< std::pair<std::string, boost::recursive_variant_>, boost::multi_index::indexed_by< boost::multi_index::ordered_non_unique< boost::multi_index::member< std::pair<std::string, boost::recursive_variant_>, std::string, &std::pair<std::string, boost::recursive_variant_>::first > >, boost::multi_index::random_access<> > > >::type variant_type; typedef boost::multi_index_container< std::pair<std::string, variant_type>, boost::multi_index::indexed_by< boost::multi_index::ordered_non_unique< boost::multi_index::member< std::pair<std::string, variant_type>, std::string, &std::pair<std::string, variant_type>::first > >, boost::multi_index::random_access<> > > container_type; variant_type v = container_type();
Key Extractorの指定において、メンバポインタを使用しているのが問題であることは一目瞭然だ。さすがにそこまでboost::recursive_variant_の置き換えが及ばない(いや、がんばって特殊化すれば、実装することは可能だろうけれど)。
解決するためにboost::multi_index::member_offsetを用いる方法を思いつくだろう。std::pair<std::string, T>について、Tがどのような型でも&std::pair<std::string, T>::firstが一定であろうことを利用する。しかし、これもまた、うまくいかない。
typedef std::pair<std::string, boost::recursive_variant_> offsetof_type; static const size_t offset = offsetof(offsetof_type, offsetof_type::first); typedef boost::make_recursive_variant< boost::blank, double, std::string, boost::multi_index_container< std::pair<std::string, boost::recursive_variant_>, boost::multi_index::indexed_by< boost::multi_index::ordered_non_unique< boost::multi_index::member_offset< std::pair<std::string, boost::recursive_variant_>, std::string, offset > >, boost::multi_index::random_access<> > > >::type variant_type; typedef boost::multi_index_container< std::pair<std::string, variant_type>, boost::multi_index::indexed_by< boost::multi_index::ordered_non_unique< boost::multi_index::member_offset< std::pair<std::string, variant_type>, std::string, offset > >, boost::multi_index::random_access<> > > container_type; // boost::mpl::at_c<variant_type::types, 3>::type != container_type variant_type v = container_type();
うまくいかない理由は、boost::recursive_variant_の置き換えの実装上の理由にある。任意のクラスについて、クラスの全てのテンプレート引数が型である場合にのみ置き換えの対象になる。つまり、型だけでなくsize_tを引数に取るboost::multi_index::member_offsetは置き換えの対象外となる。size_t自体ではなく、boost::mpl::size_tを引数に取るmember_offsetを作れば問題は解決できるが、そもそもメンバー変数のオフセットなんか取りたくはない。
シンプルにstd::pairの(一般化すればtuple用の)Key Extractorを定義するのが良いと思う。
template <typename T_result_type, size_t T_i> struct tuple_key_extractor { typedef T_result_type result_type; template <typename T> result_type& operator()(T& source) const { return std::get<T_i>(source); // or use ADL if you want } template <typename T> result_type const& operator()(T const& source) const { return std::get<T_i>(source); // or use ADL if you want } }; typedef boost::make_recursive_variant< boost::blank, double, std::string, boost::multi_index_container< std::pair<std::string, boost::recursive_variant_>, boost::multi_index::indexed_by< boost::multi_index::ordered_non_unique< tuple_key_extractor<std::string, 0> >, boost::multi_index::random_access<> > > >::type variant_type; typedef boost::mpl::at_c<variant_type::types, 3>::type container_type; variant_type v = container_type();
すっきりした。
このページへのコメント
mZKbo8 <a href="http://wqafqwmaonuw.com/">wqafqwmaonuw</a>, [url=http://kdqefdalxszs.com/]kdqefdalxszs[/url], [link=http://itryctywptvv.com/]itryctywptvv[/link], http://dvjpdzylddho.com/