Boost.Variantは再帰可能なので最強。

typedef boost::make_recursive_variant<
  boost::blank,
  std::string,
  std::map<std::string, boost::recursive_variant_>
>::type variant0;

この場合、sizeof(v)はどうなるのか。実装依存だけど、std::mapのサイズはsizeof(v)に影響しないことは言える。ストレージ上には次の疑似コードのようにポインタとして保持される。

// 疑似コード
union u {
  boost::blank u0;
  std::string  u1;
  std::map<std::string, u>* u2;
};

recursive_variantで書き直すと、次のようになる。

struct map;
typedef boost::make_recursive_variant<
  boost::blank,
  std::string,
  boost::recursive_wrapper<map>
>::type variant1;
struct map : std::map<std::string, variant> {};

boost::recursive_warpper<T>を使うと、もれなくnew Tが付いてくる。どうしてだろう。Boost.Functionみたいにsmall object判定してくれたっていいじゃないか。もちろん、

typedef boost::make_recursive_variant<
  boost::blank,
  std::string,
  std::pair<std::string, boost::recusive_variant_>
>::type variant2;

のようなコードはサイズが定まらないから無理だけれど、

struct large_object { char data[256]; };
typedef boost::make_recursive_variant<
  boost::blank,
  std::string,
  std::map<std::string, boost::recursive_variant_>,
  large_object
>::type variant3;

みたいな場合、つまり、
  • Variant内に充分大きなストレージが確保されている。
  • 再帰する型のサイズがVariantのサイズから独立である。

場合はsmall objectにできるかもしれない。っていうか、make_recursive_variantは魔法でそういうことをやってくれてると勝手に妄想してた。なんでだろう。
  • 面倒だから?
  • 必要ないから?
  • 標準に合致しなくなる?
  • 実装上問題がある?

まあ、このあたりはMLでも後で眺めてみるとして、この挙動をどうにかしたければ、たぶん、boost/include/variant/detail/enable_recursive.hppをいじれば良いらしい。これも後でやってみる。



こっから先はrecursive_variant_を解決する部分を読んだときのメモ。
  • boost/variant/variant.hpp
    • boost::variant<typename... T>::recursive_enabled_types
    • 再帰している場合の型リスト
    • quoted_enable_recursiveでrecursive_variant_を外す
  • boost/variant/detail/enable_recursive(_fwd).hpp
    • quoted_enable_recursive<typename RecursiveVariant, typename NoWrapper = mpl::false_>
    • 単にenable_recursiveをquoteする
    • enable_recursive<T, typename RecursiveVariant, typename NoWrapper>
    • 型リストの各要素T_iについて、
    • enable_recursive<T_i, wknd_self_t, mpl::false>
    • wknd_self_tはvariant<T...>

プリプロセス済みのenable_recursive

template <typename T, typename RecursiveVariant>
struct enable_recursive<T, RecursiveVariant, mpl::false_> {
private:
  typedef typename substitute<T, RecursiveVariant, ::boost::recursive_variant_>::type t_;
public:
  typedef typename mpl::if_<
    mpl::or_<is_same<t_, T>, is_reference<t_>, is_pointer<t_> >,
    t_,
    boost::recursive_wrapper<t_>
  >::type type;
};

substituteメタ関数の結果がTかリファレンスかポインタでなければ、recursive_wrapper登場。
そしてnew Tが発生。

template <typename T, typename Dest, typename Source, typename Arity>
struct substitute {
  typedef T type;
};

template <typename Dest, typename Source>
struct substitute<Source , Dest , Source , mpl::int_<-1> > {
  typedef Dest type;
};

template <
  template < typename P1 , typename P2 > class T, typename U1, typename U2,
  typename Dest,
  typename Source
>
struct substitute<T<U1, U2>, Dest, Source, mpl::int_<(2)> > {
private:
  typedef typename substitute<U1, Dest, Source>::type u1;
  typedef typename substitute<U2, Dest, Source>::type u2;

public:
  typedef T<u1, u2> type;
};

つまり、std::map<std::string, boost::recursive_variant_>の場合、

u1 = std::string
u2 = RecursiveVariant
type = std::map<std::string, RecursiveVariant>

になる。

【2010-02-27追記】アロケータのことを忘れてた。まあ、話の筋は変わらないけれど。

このページへのコメント

8yXWl8 <a href="http://ytoaqnjmsjbl.com/">ytoaqnjmsjbl</a>, [url=http://rmqazbpnhkxt.com/]rmqazbpnhkxt[/url], [link=http://lcstmovkbqbn.com/]lcstmovkbqbn[/link], http://wbqqpgghcigh.com/

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

コメントをかく


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

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

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