fork download
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. #include <assert.h>
  5. #include <exception>
  6. #include <map>
  7. #include <memory>
  8. #include <typeindex>
  9. #include <unordered_map>
  10.  
  11. // Predefine template delegate factory
  12. template < typename R, typename... Args >
  13. class brGenericDelegate ;
  14.  
  15. // C++11 template alias to announce functor definition
  16. template < typename R, typename... Args >
  17. using brGenericDelegateType = std::function< std::shared_ptr<R>(Args...) > ;
  18.  
  19. class brDelegate
  20. {
  21. protected:
  22. brDelegate(){}
  23.  
  24. public:
  25.  
  26. virtual ~brDelegate() = default ;
  27.  
  28. template < typename R, typename... Args >
  29. static std::shared_ptr<brDelegate> create( typename brGenericDelegate<R,Args...>::functor func )
  30. {
  31. return std::make_shared<brGenericDelegate<R,Args...>>(func) ;
  32. }
  33.  
  34. template < typename R, typename... Args > std::shared_ptr<R> run( Args... args ) const
  35. {
  36. using derived_type = brGenericDelegate<R,Args...> ;
  37. return dynamic_cast< const derived_type& >(*this)(args...) ;
  38. }
  39. };
  40.  
  41. template < typename R, typename... Args >
  42. class brGenericDelegate : public brDelegate
  43. {
  44. public:
  45. using functor = brGenericDelegateType< R, Args... >;
  46. brGenericDelegate( functor f ) : fn(f) {}
  47.  
  48. std::shared_ptr<R> operator() ( Args... args ) const { return fn(args...) ; }
  49.  
  50. private:
  51. const functor fn ;
  52. };
  53.  
  54.  
  55. class brIOCContainer
  56. {
  57. private:
  58. // Define generic resolver template
  59. template < class R>
  60. class GenericResolver;
  61.  
  62. class Resolver
  63. {
  64. protected:
  65. Resolver(){}
  66.  
  67. public:
  68. /** @brief Destructor */
  69. virtual ~Resolver() = default;
  70.  
  71. template<typename R, typename ... ARGS>
  72. std::shared_ptr<R> run(ARGS&& ... args) const
  73. {
  74. using derived_type = GenericResolver<R>;
  75. auto rs = dynamic_cast< const derived_type& >(*this);
  76. return rs.template run<ARGS...>(std::forward<ARGS>(args)...);
  77. }
  78. };
  79.  
  80. template <typename T>
  81. class GenericResolver : public Resolver
  82. {
  83. public:
  84. GenericResolver(std::shared_ptr<brDelegate> delegate)
  85. :m_delegate(delegate){}
  86.  
  87. virtual ~GenericResolver() = default;
  88.  
  89. template<typename ... ARGS>
  90. std::shared_ptr<T> run(ARGS&& ... args) const
  91. {
  92. return //std::make_shared<T>(
  93. m_delegate->run<T, ARGS...>(std::forward<ARGS>(args)...);
  94. //);
  95. }
  96.  
  97. std::shared_ptr<brDelegate> getDelegate(void) const {
  98. return m_delegate;
  99. }
  100.  
  101. private:
  102. std::shared_ptr<brDelegate> m_delegate = nullptr;
  103. };
  104.  
  105. class Component
  106. {
  107. public:
  108. Component(std::type_index type) : m_type(type){}
  109. ~Component(){}
  110.  
  111. std::type_index getType(void) const {
  112. return m_type;
  113. }
  114.  
  115. std::shared_ptr<Resolver> getResolver(void){
  116. return m_resolver;
  117. }
  118.  
  119. void setResolver(std::shared_ptr<Resolver> resolver){
  120. m_resolver = resolver;
  121. }
  122.  
  123. private:
  124. std::type_index m_type;
  125. std::shared_ptr<Resolver> m_resolver = nullptr;
  126. };
  127.  
  128. public:
  129. typedef std::multimap<std::type_index, std::shared_ptr<Component>> RegistryLookup_t;
  130. typedef std::pair<std::type_index, std::shared_ptr<Component>> RegistryEntry_t;
  131.  
  132. public:
  133. brIOCContainer(){}
  134. brIOCContainer(const brIOCContainer& copy){
  135. m_repository = copy.m_repository;
  136. }
  137. virtual ~brIOCContainer(){}
  138.  
  139. template <typename T>
  140. void registerType(void);
  141.  
  142. template <typename T, typename C>
  143. void registerByContract(void);
  144.  
  145. template <typename T, typename ... ARGS>
  146. std::shared_ptr<T> resolve(ARGS&& ... args) const;
  147.  
  148. template <typename T>
  149. bool contains(void) const;
  150.  
  151. template <typename T, typename C>
  152. bool contains(void) const;
  153.  
  154. private:
  155. template <typename T>
  156. void validate(void);
  157.  
  158. RegistryLookup_t::const_iterator find(std::type_index type) const{
  159. auto iter = m_repository.begin();
  160. while(iter!=m_repository.end()){
  161. if((iter->first) == type ||
  162. (iter->second)->getType() == type){
  163. break;
  164. }
  165. iter++;
  166. }
  167. return iter;
  168. }
  169.  
  170. /** Registered elements */
  171. RegistryLookup_t m_repository;
  172. };
  173.  
  174. template <typename T>
  175. inline void brIOCContainer::registerType(void)
  176. {
  177. // check if type has been already registered
  178. auto iter = this->find(typeid(T));
  179. if(iter!=m_repository.end()){
  180. std::string msg = "[brIOCContainer]:registerType: A type: <";
  181. msg.append(typeid(T).name());
  182. msg.append("> has been already registered!");
  183. throw std::runtime_error(msg.c_str());
  184. }
  185.  
  186. // create delegate for transient object creation
  187. auto delegate = brDelegate::create<T>([]() -> std::shared_ptr<T> { return std::make_shared<T>(); });
  188.  
  189. // create component and register resolver using defined delegate
  190. auto component = std::make_shared<Component>(typeid(T));
  191. component->setResolver(std::make_shared<GenericResolver<T>>(delegate));
  192. m_repository.insert(RegistryEntry_t(typeid(T), component));
  193. }
  194.  
  195. template <typename T, typename C>
  196. inline void brIOCContainer::registerByContract(void)
  197. {
  198. // check if contract and type definitions are compatible
  199. assert((std::is_base_of<C,T>::value));
  200.  
  201. // check if type is already registered by contract
  202. if((this->contains<T,C>())){
  203. std::string msg = "[brIOCContainer]:registerByContract: An unnamed type: <";
  204. msg.append(typeid(T).name());
  205. msg.append("> has been already registered by contract!");
  206. throw std::runtime_error(msg.c_str());
  207. }
  208.  
  209. // create delegate for transient object creation based on concrete type
  210. auto delegate = brDelegate::create<C>([]() -> std::shared_ptr<C> {
  211. //return dynamic_pointer_cast<C>(std::make_shared<T>());
  212. return std::make_shared<T>();
  213. });
  214.  
  215. /* Set up component of the concrete type T and register this component
  216. using the contract type */
  217. auto component = std::make_shared<Component>(typeid(C));
  218. component->setResolver(std::make_shared<GenericResolver<C>>(delegate));
  219. m_repository.insert(RegistryEntry_t(typeid(C), component));
  220. }
  221.  
  222. template <typename T, typename ... ARGS>
  223. inline std::shared_ptr<T> brIOCContainer::resolve(ARGS&& ... args) const
  224. {
  225. std::type_index type = typeid(T);
  226. /*if(std::is_abstract<T>::value){
  227. std::string msg = "[brIOCContainer]:resolve: Cant resolve object of abstract type: ";
  228. msg.append(type.name());
  229. throw std::runtime_error(msg.c_str());
  230. }*/
  231.  
  232. auto iter = this->find(type);
  233. if(iter==m_repository.end()){
  234. std::string msg = "[brIOCContainer]:resolve: No entry found for requested class type: ";
  235. msg.append(type.name());
  236. throw std::runtime_error(msg.c_str());
  237. }
  238.  
  239. auto resolver = (iter->second)->getResolver();
  240. return resolver->run<T, ARGS...>(std::forward<ARGS>(args)...);
  241. }
  242.  
  243. template <typename T>
  244. inline bool brIOCContainer::contains(void) const
  245. {
  246. std::type_index type = typeid(T);
  247. auto iter = m_repository.find(type);
  248. return iter!=m_repository.end() ? true : false;
  249. }
  250.  
  251. template <typename T, typename C>
  252. inline bool brIOCContainer::contains(void) const
  253. {
  254. bool result = false;
  255. std::type_index type = typeid(T);
  256.  
  257. for(auto range = m_repository.equal_range(typeid(C));
  258. range.first != range.second; ++range.first){
  259.  
  260. if(type == (range.first->second)->getType()){
  261. result = true;
  262. break;
  263. }
  264. }
  265. return result;
  266. }
  267.  
  268. class IVehicle
  269. {
  270. public:
  271. IVehicle(){}
  272. virtual ~IVehicle() = default;
  273.  
  274. virtual const std::string& getBrand(void) const = 0;
  275. };
  276.  
  277. class Car : public IVehicle
  278. {
  279. public:
  280. Car():IVehicle(){}
  281. Car(const std::string& name):IVehicle(), m_name(name){}
  282.  
  283. const std::string& getBrand(void) const override{
  284. return m_name;
  285. }
  286.  
  287. private:
  288. std::string m_name = "Mustang GT 500";
  289. };
  290.  
  291. class Truck : public IVehicle
  292. {
  293. public:
  294. Truck():IVehicle(){}
  295. Truck(const std::string& name):IVehicle(), m_name(name){}
  296.  
  297. const std::string& getBrand(void) const override{
  298. return m_name;
  299. }
  300.  
  301. private:
  302. std::string m_name = "MAN TGX EfficientLine 2 in long-haul transport";
  303. };
  304.  
  305.  
  306. int main() {
  307.  
  308. brIOCContainer container;
  309. container.registerType<Truck>();
  310.  
  311. auto truck = container.resolve<Truck>();
  312. std::cout << "Got a truck: " << truck->getBrand() << std::endl;
  313.  
  314. container.registerType<Car>();
  315.  
  316. // This resolve is working
  317. auto car1 = container.resolve<Car>();
  318. std::cout << "Got a vehicle: " << car1->getBrand() << std::endl;
  319.  
  320. container.registerByContract<Car, IVehicle>();
  321.  
  322. // This resolve occurs in a compiler failure
  323. auto car2 = container.resolve<IVehicle>();
  324. std::cout << "Got a vehicle: " << car2->getBrand() << std::endl;
  325.  
  326. return 0;
  327. }
Success #stdin #stdout 0s 3452KB
stdin
Standard input is empty
stdout
Got a truck: MAN TGX EfficientLine 2 in long-haul transport
Got a vehicle: Mustang GT 500
Got a vehicle: Mustang GT 500