fork download
  1. #include <stdio.h>
  2.  
  3. #include <algorithm> // for std::swap
  4.  
  5. // Preprocessor
  6. //
  7. #define PP_REPEAT_0(exp,sep) exp(0)
  8. #define PP_REPEAT_1(exp,sep) sep(PP_REPEAT_0(exp,sep),exp(1))
  9. #define PP_REPEAT_2(exp,sep) sep(PP_REPEAT_1(exp,sep),exp(2))
  10. #define PP_REPEAT_3(exp,sep) sep(PP_REPEAT_2(exp,sep),exp(3))
  11. #define PP_REPEAT_4(exp,sep) sep(PP_REPEAT_3(exp,sep),exp(4))
  12. #define PP_REPEAT_5(exp,sep) sep(PP_REPEAT_4(exp,sep),exp(5))
  13. #define PP_REPEAT(n,exp,sep) PP_REPEAT_##n(exp,sep)
  14.  
  15. #define PP_REPEAT_FROM_1_TO_1(exp,sep) exp(1)
  16. #define PP_REPEAT_FROM_1_TO_2(exp,sep) sep(PP_REPEAT_FROM_1_TO_1(exp,sep),exp(2))
  17. #define PP_REPEAT_FROM_1_TO_3(exp,sep) sep(PP_REPEAT_FROM_1_TO_2(exp,sep),exp(3))
  18. #define PP_REPEAT_FROM_1_TO_4(exp,sep) sep(PP_REPEAT_FROM_1_TO_3(exp,sep),exp(4))
  19. #define PP_REPEAT_FROM_1_TO_5(exp,sep) sep(PP_REPEAT_FROM_1_TO_4(exp,sep),exp(5))
  20. #define PP_REPEAT_FROM_1_TO_6(exp,sep) sep(PP_REPEAT_FROM_1_TO_5(exp,sep),exp(6))
  21. #define PP_REPEAT_FROM_1_TO(n,exp,sep) PP_REPEAT_FROM_1_TO_##n(exp,sep)
  22.  
  23. #define PP_SPACE(x,y) x y
  24. #define PP_COMMA(x,y) x, y
  25. #define PP_SEMICOLON(x,y) x; y
  26.  
  27. #define PP_DEC1 0
  28. #define PP_DEC2 1
  29. #define PP_DEC3 2
  30. #define PP_DEC4 3
  31. #define PP_DEC5 4
  32. #define PP_DEC6 5
  33. #define PP_DEC(x) PP_DEC##x
  34.  
  35. // Typelist
  36. //
  37. #define TEMPLATE_PARAM_NAME(n) T##n
  38. #define TEMPLATE_PARAM(n) class T##n
  39. #define TEMPLATE_PARAM_NULLTYPE(n) class T##n = NullType
  40.  
  41. #define TYPELIST_PARAM_NAMES PP_REPEAT(5,TEMPLATE_PARAM_NAME,PP_COMMA)
  42. #define TYPELIST_PARAMS PP_REPEAT(5,TEMPLATE_PARAM,PP_COMMA)
  43. #define TYPELIST_PARAMS_NULLTYPE PP_REPEAT(5,TEMPLATE_PARAM_NULLTYPE,PP_COMMA)
  44.  
  45. struct NullType;
  46.  
  47. template<class, class> struct Typelist;
  48.  
  49. template<TYPELIST_PARAMS_NULLTYPE>
  50. struct MakeTypelist
  51. {
  52. typedef Typelist<T0, typename MakeTypelist<PP_REPEAT_FROM_1_TO(5,TEMPLATE_PARAM_NAME,PP_COMMA)>::Result> Result;
  53. };
  54.  
  55. template<>
  56. struct MakeTypelist<>
  57. {
  58. typedef NullType Result;
  59. };
  60.  
  61. template<class TList> struct Length;
  62.  
  63. template<>
  64. struct Length<NullType>
  65. {
  66. static const size_t value = 0;
  67. };
  68.  
  69. template<class T, class U>
  70. struct Length<Typelist<T, U> >
  71. {
  72. static const size_t value = 1 + Length<U>::value;
  73. };
  74.  
  75. template<class TList, unsigned int index> struct TypeAt;
  76.  
  77. template<class Head, class Tail>
  78. struct TypeAt<Typelist<Head, Tail>, 0>
  79. {
  80. typedef Head Result;
  81. };
  82.  
  83. template<class Head, class Tail, unsigned int i>
  84. struct TypeAt<Typelist<Head, Tail>, i>
  85. {
  86. typedef typename TypeAt<Tail, i - 1>::Result Result;
  87. };
  88.  
  89. template<class TList, class T> struct IndexOf;
  90.  
  91. template<class T> struct IndexOf<NullType, T> {};
  92.  
  93. template<class T, class Tail>
  94. struct IndexOf<Typelist<T, Tail>, T>
  95. {
  96. static const int value = 0;
  97. };
  98.  
  99. template<class Head, class Tail, class T>
  100. struct IndexOf<Typelist<Head, Tail>, T>
  101. {
  102. static const int value = 1 + IndexOf<Tail, T>::value;
  103. };
  104.  
  105. // Selector
  106. //
  107. #define SELECTOR_CASE(n) \
  108. case n: return visitor(*static_cast<typename TypeAt<TList, n>::Result*>(storage))
  109.  
  110. #define SELECTOR_CASES_ENUM(n) PP_REPEAT(n,SELECTOR_CASE,PP_SEMICOLON)
  111.  
  112. #define SELECTOR_ENUM(n) \
  113. template<> \
  114. struct Selector<n> \
  115. { \
  116. template<class TList, class Visitor> \
  117. static typename Visitor::ResultType apply(Visitor visitor, unsigned char which, void* storage) \
  118. { \
  119. switch (which) \
  120. { \
  121. SELECTOR_CASES_ENUM(PP_DEC(n)); \
  122. } \
  123. } \
  124. }
  125.  
  126. template<size_t> struct Selector;
  127.  
  128. PP_REPEAT_FROM_1_TO(6,SELECTOR_ENUM,PP_SEMICOLON);
  129.  
  130. // Variant
  131. //
  132. template<TYPELIST_PARAMS_NULLTYPE>
  133. class Variant
  134. {
  135. public:
  136.  
  137. template<class T>
  138. Variant(T const &t)
  139. : which_(IndexOf<internal_types, T>::value)
  140. , storage_(new T(t))
  141. {
  142. }
  143.  
  144. ~Variant()
  145. {
  146. apply(Destroyer());
  147. }
  148.  
  149. Variant(Variant const &other)
  150. : which_(other.which_)
  151. , storage_(other.apply(CopyConstructHelper()))
  152. {
  153. }
  154.  
  155. template<class Visitor>
  156. typename Visitor::ResultType apply(Visitor visitor) const
  157. {
  158. return Selector<Length<internal_types>::value>::template apply<internal_types>(visitor, which_, storage_);
  159. }
  160.  
  161. void swap(Variant &other)
  162. {
  163. std::swap(which_, other.which_);
  164. std::swap(storage_, other.storage_);
  165. }
  166.  
  167. template<class T>
  168. void operator=(T const &t)
  169. {
  170. Variant(t).swap(*this);
  171. }
  172.  
  173. private:
  174.  
  175. typedef typename MakeTypelist<TYPELIST_PARAM_NAMES>::Result internal_types;
  176.  
  177. struct Destroyer
  178. {
  179. typedef void ResultType;
  180.  
  181. template<class T>
  182. void operator()(T &t) const
  183. {
  184. delete &t;
  185. }
  186. };
  187.  
  188. struct CopyConstructHelper
  189. {
  190. typedef void* ResultType;
  191.  
  192. template<class T>
  193. void* operator()(T const &t) const
  194. {
  195. return new T(t);
  196. }
  197. };
  198.  
  199. unsigned char which_;
  200. void* storage_;
  201. };
  202.  
  203. template<class T>
  204. struct StaticVisitor
  205. {
  206. typedef T ResultType;
  207. };
  208.  
  209. template<class A>
  210. struct less_visitor : StaticVisitor<bool>
  211. {
  212. A a_;
  213.  
  214. less_visitor(A const &a) : a_(a) {}
  215.  
  216. template<class U>
  217. bool operator()(U const &u) const
  218. {
  219. return u < a_;
  220. }
  221. };
  222.  
  223. #define TEMPLATE_PARAM_A(n) class A##n
  224. #define TEMPLATE_PARAM_NAME_A(n) A##n
  225. #define FUNCTION_PARAM(n) A##n a##n
  226. #define FUNCTION_ARG(n) a##n
  227.  
  228. template<TYPELIST_PARAMS, class A>
  229. Variant<TYPELIST_PARAM_NAMES>& max_helper(Variant<TYPELIST_PARAM_NAMES> &u, A a)
  230. {
  231. if (u.apply(less_visitor<A>(a))) // u < a
  232. u = a;
  233. return u;
  234. }
  235.  
  236. #define MAX_HELPER_ENUM(n) \
  237. template<TYPELIST_PARAMS, PP_REPEAT(n,TEMPLATE_PARAM_A,PP_COMMA)> \
  238. Variant<TYPELIST_PARAM_NAMES>& max_helper(Variant<TYPELIST_PARAM_NAMES> &u, PP_REPEAT(n,FUNCTION_PARAM,PP_COMMA)) \
  239. { \
  240. return max_helper(max_helper(u, a0), PP_REPEAT_FROM_1_TO(n,FUNCTION_ARG,PP_COMMA)); \
  241. }
  242.  
  243. #define MAX_ENUM(n) \
  244. template<PP_REPEAT(n,TEMPLATE_PARAM_A,PP_COMMA)> \
  245. Variant<PP_REPEAT(n,TEMPLATE_PARAM_NAME_A,PP_COMMA)> max(PP_REPEAT(n,FUNCTION_PARAM,PP_COMMA)) \
  246. { \
  247. Variant<PP_REPEAT(n,TEMPLATE_PARAM_NAME_A,PP_COMMA)> u(a0); \
  248. return max_helper(u, PP_REPEAT_FROM_1_TO(n,FUNCTION_ARG,PP_COMMA)); \
  249. }
  250.  
  251. // TODO: PP_REPEAT_FROM_1_TO(4,MAX_HELPER_ENUM,PP_SPACE)
  252. MAX_HELPER_ENUM(1)
  253. MAX_HELPER_ENUM(2)
  254. MAX_HELPER_ENUM(3)
  255. MAX_HELPER_ENUM(4)
  256.  
  257. // TODO: PP_REPEAT_FROM_1_TO(5,MAX_ENUM,PP_SPACE)
  258. MAX_ENUM(1)
  259. MAX_ENUM(2)
  260. MAX_ENUM(3)
  261. MAX_ENUM(4)
  262. MAX_ENUM(5)
  263.  
  264. struct Println : StaticVisitor<void>
  265. {
  266. void operator()(int i) const
  267. {
  268. printf("int %d\n", i);
  269. }
  270.  
  271. void operator()(float f) const
  272. {
  273. printf("float %f\n", f);
  274. }
  275.  
  276. void operator()(double d) const
  277. {
  278. printf("double %f\n", d);
  279. }
  280. };
  281.  
  282. int main()
  283. {
  284. max(3, 3.14f).apply(Println()); // float 3.140000
  285. max(3, 3.14f, 3.0).apply(Println()); // float 3.140000
  286. max(3, 3.14f, 4.0).apply(Println()); // double 4.000000
  287. max(3, 5, 3.14f, 4.0).apply(Println()); // int 5
  288.  
  289. return 0;
  290. }
  291.  
Success #stdin #stdout 0.02s 2816KB
stdin
Standard input is empty
stdout
float 3.140000
float 3.140000
double 4.000000
int 5