2017-09-25 15 views
3

私は何らかの種類のDIコンテナをC++で書いています。現代のC++のエイリアスを別のタイプから別のエイリアスにすることができれば興味があります。 私が基本的にしたいことは、エイリアスインターフェイスで実装コンストラクタを呼び出すことができることです。これと同じように:あるタイプから別のタイプへのエイリアスの作成

di::Register<Interface, Impl>(); 
di::Resolve<Interface>(); // -> Impl should be resolved 

問題は、私がこれまでにコンパイル時にエイリアスインターフェイスとImplをする方法を見つけることができなかったことです。私はRTTIを使ってこれを行うことができますが、実際には使用したくありません。まったく可能ですか?

+0

あなたがかもしれません[\ [Boost \] .DI](https://github.com/boost-experimental/di)のようなものを通して楽しく読んでください。 – chris

+0

実際に私の[DIコンテナライブラリ](https://github.com/gracicot/kangaru/wiki/03.-Override-Services#default-service-type)で 'kgr :: Default'を使って非常によく似たものを作成しました –

+0

@GuillaumeRacicotはい、しかし、私はこのケースで継承を使用したくない、私はそれが非常にかさばるインターフェイスを作ると思う。 – s0nicYouth

答えて

0

問題は、これまでコンパイル時にInterfaceとImplのエイリアスを見つけることができなかったことです。私はRTTIを使ってこれを行うことができますが、実際には使用したくありません。まったく可能ですか?

私はあなたの目標を正しく理解していると仮定すると、これを行うために使用できるトリックがあります。それはあなたがそこに持っているもののように見栄えはありません。

http://stackoverflow.com/questions/4790721/c-type-registration-at-compile-time-trick

このトリックは、マット・カラブレーゼに起因していた、彼はa Boostcon talk in like 2011でそれを説明しました。

このトリックは標準に準拠していますが、いくつかのヘッダーファイルで登録を開始してからCPPファイルで登録を続けると、ODR違反が発生する可能性がありますあなたは不注意です。

私は、例えば、あなたが

REGISTER_PAIR(interface, impl); 

のようないくつかのマクロで終わるだろうと、あなたは、いくつかの型の別名を持っていると思う

get_registered_impl_t<interface> 

これはimplに解決されます。

この例では、時間の経過とともに蓄積されるタイプのリストを作成する方法を示しています。あなたの場合、それはタイプレベルの "ペア"のリストになり、リニアスキャンを行うことでそれを検索することができます。複雑なコンパイル時のマップデータ構造を使用しようとすることもできますが、ほとんどの場合、リニアスキャンは十分速く、リストの長さはコンパイラの最大テンプレートインスタンス化の深さによって制限されます典型的には100または200のようなものです。大きなリストが必要な場合は、使用できるトリックがありますが、ここでは詳しく説明しません。

1

あなたは(私は積極的にお勧めしません)グローバルな状態を持っている場合は、それと逃げるべきで、あなたのコードのインタフェースを見ることによって:

using type_id_t = void(*)(); 
template<typename> void type_id() {} 

struct di { 
    using create_function_t = void*(*)(); 
    static std::unordered_map<type_id_t, create_function_t> types; 

    template<typename I, typename T> 
    static void Register() { 
     types.emplace(type_id<I>, []{ 
      return static_cast<void*>(
       static_cast<I*>(new T) 
      ); 
     }); 
    } 

    template<typename I> 
    static std::unique_ptr<I> Resolve() { 
     return std::unique_ptr<I>{static_cast<I*>(types[type_id<I>]())}; 
    } 
}; 

Live example

+0

はい、そうです。私はここでグローバルな状態を使うつもりです。私の目標は、dagger2に非常に近いものを実装することです。あなたのスニペットをありがとうが、私が言及したように私はコンパイル時にそれを実装する方法を探しています。 I = Tを使用するようなものですが、あなたのソリューションはRTTIの代わりになります。 – s0nicYouth

+0

グローバルな状態の使用はお勧めしません。特にDIの場合。このコードは、大域的な状態がなくても使いやすいです。すべての静的キーワードとボイルを削除するだけです。 –

+0

私はそれを得た。しかし私にとって、ここのグローバルな状態は問題ではない。私の質問の主な目的は、コンパイル時に型をバインドする方法を見つけることでした。私がグローバルな状態を取り除いても、不幸なことに、ソリューションはこれを実行しません。 – s0nicYouth

関連する問題