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の通りにしたほうが良いかもしれない。

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/

0
Posted by jvbkoa 2013年11月14日(木) 10:13:59 返信

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

メンバーのみ編集できます