Last active
January 2, 2024 00:16
-
-
Save Jiwan/aefcb797c31911377b1c1c679ca5f1cd to your computer and use it in GitHub Desktop.
Revisions
-
Jiwan revised this gist
May 31, 2019 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -153,7 +153,7 @@ struct Concret : Interface struct C { C(B& b, Interface& i, A& a) : i(i) {} void SayHi() { i.SayHi(); -
Jiwan revised this gist
May 31, 2019 . 1 changed file with 5 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -8,6 +8,9 @@ #include <utility> #include <unordered_map> // ***** IMPLEMENTATION **** struct base_instance_container { virtual ~base_instance_container() = default; @@ -121,6 +124,8 @@ struct dependency_injector std::unordered_map<std::type_index, std::unique_ptr<base_instance_container>> instances_; }; // ***** TEST SCENARIO **** struct A { }; -
Jiwan created this gist
May 31, 2019 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,167 @@ #include <cassert> #include <iostream> #include <functional> #include <memory> #include <type_traits> #include <typeinfo> #include <typeindex> #include <utility> #include <unordered_map> struct base_instance_container { virtual ~base_instance_container() = default; }; template <class T> struct instance_container : base_instance_container { instance_container(std::unique_ptr<T> p) : p(std::move(p)) { } std::unique_ptr<T> p; }; struct dependency_injector; template <class T> struct generic_argument { template < class Type, std::enable_if_t< !std::is_same<T, std::decay_t<Type>>::value, int > = 0 > constexpr operator Type&() const noexcept { return injector_. template create<Type>(); } dependency_injector& injector_; }; template <class T, class... arguments> constexpr auto create_impl(dependency_injector& di) -> std::enable_if_t<std::is_constructible<T, arguments...>::value, std::unique_ptr<instance_container<T>>> { return std::make_unique<instance_container<T>>(std::make_unique<T>(arguments{di}...)); } template <class T, class... arguments> constexpr auto create_impl(dependency_injector& di) -> std::enable_if_t<!std::is_constructible<T, arguments...>::value, std::unique_ptr<instance_container<T>>> { return create_impl<T, arguments..., generic_argument<T>>(di); } struct dependency_injector { template <class T> T& create() { // Check if there is already an instance of that type std::cout << "Querying a instance of type: " << typeid(T).name() << std::endl; auto typeindex = std::type_index{typeid(T)}; auto it = instances_.find(typeindex); if (it != instances_.end()) { std::cout << "Instance already existing: " << typeid(T).name() << std::endl; return *static_cast<instance_container<T>*>(it->second.get())->p; } else { std::cout << "Instance does not exist, creating it for you: " << typeid(T).name() << std::endl; return do_create<T>(); } } template <class Interface, class Concret> void implement() { creator_.emplace(std::type_index{typeid(Interface)}, [this]() { std::cout << "Creating " << typeid(Interface).name() << " with concret type: " << typeid(Concret).name() << std::endl; instances_.emplace(std::type_index{typeid(Interface)}, create_impl<Concret>(*this)); }); } private: template <class T, std::enable_if_t<!std::is_abstract<T>::value, int> = 0> T& do_create() { auto typeindex = std::type_index{typeid(T)}; auto creator_it = creator_.find(std::type_index{typeid(T)}); if (creator_it != creator_.end()) { std::cout << "Instance created using a creator: " << typeid(T).name() << std::endl; creator_it->second(); return *static_cast<instance_container<T>*>(instances_[std::type_index{typeid(T)}].get())->p; } else { auto result = instances_.emplace(typeindex, create_impl<T>(*this)); std::cout << "Instance created manually: " << typeid(T).name() << std::endl; return *static_cast<instance_container<T>*>(result.first->second.get())->p; } } // Abstract types need a special treatment to avoid making create_impl crazy and detecting interfaces without concret classes... template <class T, std::enable_if_t<std::is_abstract<T>::value, int> = 0> T& do_create() { auto typeindex = std::type_index{typeid(T)}; auto creator_it = creator_.find(std::type_index{typeid(T)}); if (creator_it != creator_.end()) { std::cout << "Instance created using a creator: " << typeid(T).name() << std::endl; creator_it->second(); return *static_cast<instance_container<T>*>(instances_[std::type_index{typeid(T)}].get())->p; } else { assert(false && "No concret class provided"); } } std::unordered_map<std::type_index, std::function<void()>> creator_; std::unordered_map<std::type_index, std::unique_ptr<base_instance_container>> instances_; }; struct A { }; struct B { }; struct Interface { virtual ~Interface() = default; virtual void SayHi() = 0; }; struct Concret : Interface { Concret(A& a) {} void SayHi() override { std::cout << "Hi" << std::endl; } }; struct C { C(B& b, Interface& i, A& a) : i(i) {} void SayHi() { i.SayHi(); } Interface& i; }; int main() { dependency_injector di; di.implement<Interface, Concret>(); auto& c = di.create<C>(); c.SayHi(); }