2011-01-25 10 views
9

私は次のような状況に陥っています:コンパイル時に登録/コンパイルするためのboost :: mpl :: vectorのような種類の(functor)がたくさんあるとします。 うまくやってみるにはどんなトリックがありますか?コンパイル時にC++の型式を登録する

私が望むのは、マクロがタイプインしてコンパイラに入るfunctorタイプと登録ファイルを実装するhppファイルです。

// registered.hpp 
REGISTER("functor1.hpp") // implementation 
REGISTER("functor2.hpp") 
... 
boost::mpl::vector<...> types; // full registration vector 

例えば

うまくいけば、それは理にかなっています。 ありがとうございます

答えて

16

型を1つずつ登録し、それらのすべてをmpl :: vectorなどの形式で取得する方法があります。私はブーストメーリングリストでこのトリックを学んだことがある(おそらくDave Abrahamsから、私は確かに思い出すことはできないが)。

編集:私はスライド28からhttps://github.com/boostcon/2011_presentations/raw/master/thu/Boost.Generic.pdfに学びました。

私はコードにMPLを使用して自己完結型にしません。

// The maximum number of types that can be registered with the same tag. 
enum { kMaxRegisteredTypes = 10 }; 

template <int N> 
struct Rank : Rank<N - 1> {}; 

template <> 
struct Rank<0> {}; 

// Poor man's MPL vector. 
template <class... Ts> 
struct TypeList { 
    static const int size = sizeof...(Ts); 
}; 

template <class List, class T> 
struct Append; 

template <class... Ts, class T> 
struct Append<TypeList<Ts...>, T> { 
    typedef TypeList<Ts..., T> type; 
}; 

template <class Tag> 
TypeList<> GetTypes(Tag*, Rank<0>) { return {}; } 

// Evaluates to TypeList of all types previously registered with 
// REGISTER_TYPE macro with the same tag. 
#define GET_REGISTERED_TYPES(Tag) \ 
    decltype(GetTypes(static_cast<Tag*>(nullptr), Rank<kMaxRegisteredTypes>())) 

// Appends Type to GET_REGISTERED_TYPES(Tag). 
#define REGISTER_TYPE(Tag, Type)        \ 
    inline Append<GET_REGISTERED_TYPES(Tag), Type>::type  \ 
    GetTypes(Tag*, Rank<GET_REGISTERED_TYPES(Tag)::size + 1>) { \ 
    return {};            \ 
    }               \ 
    static_assert(true, "") 

使用例:

struct IntegralTypes; 
struct FloatingPointTypes; 

// Initially both type lists are empty. 
static_assert(std::is_same<GET_REGISTERED_TYPES(IntegralTypes), TypeList<>>::value, ""); 
static_assert(std::is_same<GET_REGISTERED_TYPES(FloatingPointTypes), TypeList<>>::value, ""); 

// Add something to both lists. 
REGISTER_TYPE(IntegralTypes, int); 
REGISTER_TYPE(FloatingPointTypes, float); 
static_assert(std::is_same<GET_REGISTERED_TYPES(IntegralTypes), TypeList<int>>::value, ""); 
static_assert(std::is_same<GET_REGISTERED_TYPES(FloatingPointTypes), TypeList<float>>::value, ""); 

// Add more types. 
REGISTER_TYPE(IntegralTypes, long); 
REGISTER_TYPE(FloatingPointTypes, double); 
static_assert(std::is_same<GET_REGISTERED_TYPES(IntegralTypes), TypeList<int, long>>::value, ""); 
static_assert(std::is_same<GET_REGISTERED_TYPES(FloatingPointTypes), TypeList<float, double>>::value, ""); 
+0

メーリングリストのスレッドへのリンクがありますか? – Xeo

+0

残念ながら、私はトリックを学んだ元のスレッドを見つけることができません。 –

0

私はマクロを使用しません。通常の方法は、登録を初期化するオブジェクトを定義することです。落とし穴:あなたは何かを参照する必要があります。それはにリンクさせるためには、コンパイル単位内で、関数を呼び出します。

乾杯& HTH。、

+0

理想的には私は1本のラインを持つ容器にすべてのこれらのタイプを入れたいと思います。私は2-3行でそれ以外のことをすることができますが、私はトリックがあるかどうかを知りたいと思います。 – Anycorn

-3

あなたはMPL ::ベクトルのアイデアを解決することは決してないだろう。テンプレートの「変数」は変更できません。テンプレートのメタプログラミングは純粋な関数型言語であることを忘れないでください。副作用はまったくありません。

登録しています...マクロのものは正常に動作します。登録プロセスで小さなグローバル変数を宣言して初期化するようにマクロを定義します。あなたは、ライブラリでそれをやろうとしている場合

How to force inclusion of "unused" object definitions in a library

注修正:別の方法としては、私がここにいた道を行くことができます。

+0

私のアイデアは、最初の登録 - > types1、types2を作るための2番目の追加などです... finaly typedef typesN to types。 – Anycorn

+1

'mpl :: for_each'は実行時に副作用を与えます。おそらく、あなたは何か役に立つかもしれない型の 'mpl :: vector'を構築することができます。おそらく何らかのポリシーチェーンがありますか?とにかく、 'for_each'と' fold'ファミリーの両方は、実行時の効果を持つことができる構造体を構築することを可能にします。私の大好きなのは、mpl :: contraintに対してテストを行い、carのメンバーを呼び出したり、cdrの車を呼び出したりして、cons car/cdrタイプのテンプレートを作ることです。 – KitsuneYMG

+0

@ymg - はい、複数の独立した場所からmplシーケンスを構築する方法はありません。あなたができることは、配列をどこかに定義して使用することだけです。だから、「登録」というテーマは起こりません。単純にファクトリをサブクラス化し、型をそのコンストラクタにハードコーディングするより効率的ではありません。それほど実際にはありません。 –