fork download
  1. #include <tuple>
  2. #include <memory>
  3. #include <string>
  4. #include <iostream>
  5. #include <unordered_map>
  6. #include <typeinfo>
  7. #include <typeindex>
  8. #include <functional>
  9.  
  10. // -----
  11.  
  12. class Arguments {
  13. public:
  14. struct ArgTupleBase
  15. {
  16. };
  17.  
  18. template<typename... Ts>
  19. struct ArgTuple : public ArgTupleBase {
  20. std::tuple<Ts...> args;
  21.  
  22. ArgTuple(Ts... ts) : args(std::make_tuple(ts...))
  23. {
  24. }
  25.  
  26. // -----
  27.  
  28. const std::tuple<Ts...>& get() const
  29. {
  30. return args;
  31. }
  32. };
  33.  
  34. // -----
  35.  
  36. template<typename... Ts>
  37. Arguments(Ts... ts) : args(new ArgTuple<Ts...>(ts...)), valid(sizeof...(ts) != 0)
  38. {
  39. }
  40.  
  41. // -----
  42.  
  43. // Indicates whether it holds any valid arguments.
  44. explicit operator bool() const
  45. {
  46. return valid;
  47. }
  48.  
  49. // -----
  50.  
  51. const std::unique_ptr<ArgTupleBase>& get() const
  52. {
  53. return args;
  54. }
  55.  
  56. private:
  57. std::unique_ptr<ArgTupleBase> args;
  58. bool valid;
  59. };
  60.  
  61. // -----
  62.  
  63. // Two example components.
  64. class One {
  65. int i;
  66. bool b;
  67.  
  68. public:
  69. One(int i, bool b) : i(i), b(b) {}
  70.  
  71. static void* create(const Arguments& arg_holder)
  72. {
  73. // Insert parameter types here.
  74. auto& args
  75. = static_cast<Arguments::ArgTuple<int, bool>&>(*(arg_holder.get())).get();
  76.  
  77. if (arg_holder)
  78. {
  79. return new One(std::get<0>(args), std::get<1>(args));
  80. }
  81. else
  82. {
  83. // Insert default parameters (if any) here.
  84. return new One(0, false);
  85. }
  86. }
  87.  
  88. // Testing function.
  89. friend std::ostream& operator<<(std::ostream& os, const One& one)
  90. {
  91. return os << "One, with "
  92. << one.i
  93. << " and "
  94. << std::boolalpha << one.b << std::noboolalpha
  95. << ".\n";
  96. }
  97. };
  98. std::ostream& operator<<(std::ostream& os, const One& one);
  99.  
  100.  
  101. class Two {
  102. char c;
  103. double d;
  104.  
  105. public:
  106. Two(char c, double d) : c(c), d(d) {}
  107.  
  108. static void* create(const Arguments& arg_holder)
  109. {
  110. // Insert parameter types here.
  111. auto& args
  112. = static_cast<Arguments::ArgTuple<char, double>&>(*(arg_holder.get())).get();
  113.  
  114. if (arg_holder)
  115. {
  116. return new Two(std::get<0>(args), std::get<1>(args));
  117. }
  118. else
  119. {
  120. // Insert default parameters (if any) here.
  121. return new Two('\0', 0.0);
  122. }
  123. }
  124.  
  125. // Testing function.
  126. friend std::ostream& operator<<(std::ostream& os, const Two& two)
  127. {
  128. return os << "Two, with "
  129. << (two.c == '\0' ? "null" : std::string{ 1, two.c })
  130. << " and "
  131. << two.d
  132. << ".\n";
  133. }
  134. };
  135. std::ostream& operator<<(std::ostream& os, const Two& two);
  136.  
  137. // -----
  138.  
  139. // This is the world interface.
  140. class World
  141. {
  142. // Actual worker.
  143. virtual void* create_impl(const std::type_index& ctype, const Arguments& arg_holder) = 0;
  144.  
  145. // Type-to-create() map.
  146. static std::unordered_map<std::type_index, std::function<void*(const Arguments&)>> creators;
  147.  
  148. public:
  149. // Templated front-end.
  150. template<typename ComponentType>
  151. ComponentType* createComponent(const Arguments& arg_holder)
  152. {
  153. return static_cast<ComponentType*>(create_impl(typeid(ComponentType), arg_holder));
  154. }
  155.  
  156. // Populate type-to-create() map.
  157. static void populate_creators() {
  158. creators[typeid(One)] = &One::create;
  159. creators[typeid(Two)] = &Two::create;
  160. }
  161. };
  162. std::unordered_map<std::type_index, std::function<void*(const Arguments&)>> World::creators;
  163.  
  164.  
  165. template<typename Allocator = std::allocator<World>>
  166. class WorldImpl : public World
  167. {
  168. void* create_impl(const std::type_index& ctype, const Arguments& arg_holder) override
  169. {
  170. return creators[ctype](arg_holder);
  171. }
  172. };
  173.  
  174. class Entity
  175. {
  176. World* world;
  177.  
  178. public:
  179. template<typename ComponentType, typename... Args>
  180. void assign(Args... args)
  181. {
  182. ComponentType* component = world->createComponent<ComponentType>(Arguments(args...));
  183.  
  184. std::cout << *component;
  185.  
  186. delete component;
  187. }
  188.  
  189. Entity() : world(new WorldImpl<>())
  190. {
  191. }
  192.  
  193. ~Entity()
  194. {
  195. if (world) { delete world; }
  196. }
  197. };
  198.  
  199. int main() {
  200. World::populate_creators();
  201.  
  202. Entity e;
  203.  
  204. e.assign<One>();
  205. e.assign<Two>();
  206.  
  207. e.assign<One>(118, true);
  208. e.assign<Two>('?', 8.69);
  209.  
  210. e.assign<One>('0', 8); // Fails; calls something like One(1075929415, true).
  211. e.assign<One>((int)'0', 8); // Succeeds.
  212. }
Success #stdin #stdout 0s 3476KB
stdin
Standard input is empty
stdout
One, with 0 and false.
Two, with null and 0.
One, with 118 and true.
Two, with ? and 8.69.
One, with -1374389712 and true.
One, with 48 and true.