2017-09-25 60 views
3

我在C++中編寫了一些DI容器,我很好奇它是否可以在現代C++中創建從一種類型到另一種類型的別名。 我基本上想要做的是能夠通過它的別名接口調用實現構造函數。像這樣:創建一個別名到另一個類型

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

的問題是,我已經無法找到到目前爲止辦法別名接口並實現了一套在編譯的時候。我可以使用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的東西。感謝您的snipet,但正如我所提到的,我正在尋找一種在編譯時實現它的方法。就像使用I = T一樣。但是您的解決方案無論如何都是RTTI的好替代品。 – s0nicYouth

+0

我不建議使用全局狀態。特別是對於DI。這段代碼在沒有任何全局狀態的情況下使用非常簡單。只需刪除所有靜態關鍵字和瞧。 –

+0

我明白了。但對我而言,這裏的全球狀態不是問題。我的問題的主要目標是找到在編譯時綁定類型的方式。即使我刪除全局狀態,不幸的是你的解決方案不會這樣做。 – s0nicYouth