2012-04-08 6 views
1

例を使用せずにこの質問にフレーズするのは少し難しいので、ちょっとしたことがあります。boostはどのようにクラスの "オプション"として型のリストを実装していますか?

基本的な例として、boost::intrusive::listには興味深いテンプレートがいくつかあり、正確にどのように動作しているかを把握するのに苦労しています。クラス仕様は少しのようになります。

template<typename T, class... Options> 
class list { 
    ... 
}; 

私の焦点はOptionsパラメータです。まず、バリデーションです。これは、言語によってサポートされているので、C++ 11では「自明」です。そして確かにC++ 03でシミュレートするのは簡単です(最大10個のパラメータ、すべてデフォルトのトークン値を持つことができます)。

は、ここに私の質問です:

Optionsは、任意の順序に "オプション" タイプ、の任意の数を取ることができます。たとえば、次のように一体、彼らはすべての異なる組み合わせのためにこの作品を作っているか

typedef list<Foo, constant_time_size<false> > FooList; 

または

//This option will configure "list" to use the member hook 
typedef member_hook<Foo, list_member_hook<>, &Foo::hook_> MemberHookOption; 

//This list will use the member hook 
typedef list<Foo, MemberHookOption> FooList; 

これは本当にクールです...。同じタイプのオプションを2回渡すとどうなりますか? boost::instrusive::listのために、可能なオプションは次のとおりです。

  • base_hook<class Hook>/member_hook<class T, class Hook, Hook T::* PtrToMember>/value_traits<class ValueTraits>:すべてのこれらのオプションは、(我々は同じTタイプのいくつかのフックを持つことができるので)リストとフックに挿入するタイプのTとの関係を指定します。 member_hookについては少し後で説明し、value_traitsについては、カスタムValueTraitsを持つコンテナのセクションで説明します。オプションが指定されていない場合、コンテナはデフォルトのタグでベースフックを使用するように設定されます。フック(ポインタのタイプ、リンクモードなど)のために設定されたいくつかのオプションは、コンテナに伝播されます。

  • constant_time_size<bool Enabled>:定数time size()関数がコンテナに対して要求されているかどうかを指定します。これは、侵入型コンテナに、コンテナの現在のサイズを追跡するために追加のメンバを格納するように指示する。デフォルトでは、一定時間サイズが有効化されています。

  • size_type<bool Enabled>:コンテナのサイズを保持できるタイプを指定します。この型は、list.size()によって返される型と、constant_time_sizeが要求された場合に侵入型コンテナに格納された型になります。ユーザーは通常この型を変更する必要はありませんが、一部のコンテナはstd :: size_tとは異なるsize_typeを持つことができます(たとえば、STLライクなコンテナはそのアロケータによって定義されたsize_typeを使用します)。 Boost.Intrusiveは、サイズの型を指定するコンテナを実装するために使用できます。デフォルトでは、型はstd :: size_tです。

この概念は、タイプの振る舞いの定義をコンパイルすることができます。しかし、あなたが想像しているように、さまざまな組み合わせが複雑になる可能性があります。私はいくつかの魔法を通して、実際のデータ構造に使用できるシンプルな構造体にオプションを正規化していると推測しています。しかし、それはちょうど推測の仕事です: - P

+0

テンプレート引数の減算を使うのは難しくないと思います。 – Cosyn

+0

@Cosyn:これはテンプレート引数の減算とは関係ありません。私はあなたがその質問を誤解しているかもしれないと思います。 –

+1

Boost.Parameterを見てください。これはBoost.Intrusiveが名前付きパラメータを作成するために使用しているものです。 –

答えて

1

ポリシーベースのデザインを試してみると、これを数回しました。

私が使っていたコアアイデアは、(イテレータのiterator_categoryに似た内部typedefを使って)ポリシーがタグ付けされていて、リストを歩いてカテゴリに与えられた方針を抽出するクラスを定義し、 2つのポリシーが同じカテゴリを参照した場合、コンパイルエラーが発生します。何かのように:if_は、単に2つの述語に基づいて種類とコンビネータの間で選択

template <typename Tag, typename Opt, typename... Options> 
struct CategoryExtractorImpl { 
    typedef typename if_< 
      same_type<typename Opt::Tag, Tag>, 
      Opt, 
      void 
    >::type Lhs; 
    typedef typename CategoryExtractorImpl<Tag, Options...>::type Rhs; 
    typedef typename Combinator<Lhs,Rhs>::type type; 
}; 

のように書かれている:もちろん

template <typename, typename> struct Combinator; 
template <typename L> struct Combinator<L, void> { typedef L type; }; 
template <typename R> struct Combinator<void, R> { typedef R type; }; 
template <> struct Combinator<void, void> { typedef void type; }; 

、あなたはまた、ケースのために、デフォルトを提供する必要がありますポリシーはまったく提供されません。

template <typename L, typename R> struct ForgivingCombinator { typedef L type; }; 
template <typename R> struct ForgivingCombinator<void, R> { typedef R type; }; 

そして最後に、あなたが得る:

これを使用して
template <typename Default, typename... Options> 
struct CategoryExtractor { 
    typedef typename ForgivingCombinator< 
     typename CategoryExtactorImpl<typename Default::Tag, Options...>::type 
     Default 
    >::type type; 
}; 

、あなたは、単に簡単にすべてのカテゴリを抽出します。もちろん

template <typename... Options> 
class List { 
    typedef typename CategoryExtractor<DefaultPolicyX, Options...>::type PolicyX; 
    typedef typename CategoryExtractor<DefaultPolicyY, Options...>::type PolicyY; 
    ... 
}; 

を、一般的なポリシーベースの設計では、それはおそらく取得します(EBOをトリガするために)個人的に継承してから、必要に応じてクラス内の実際のタイプを繰り返すため、より詳細な情報を得ることができます。

関連する問題