fork(3) download
  1. #include <cstdint>
  2. #include <iostream>
  3. #include <tuple>
  4. #include <type_traits>
  5. #include <vector>
  6.  
  7. /////////////////////////
  8.  
  9. #if 1 // multiple dispatch
  10.  
  11. // sequence of size_t // not in C++11
  12. template <std::size_t ...> struct index_sequence {};
  13.  
  14. // Create index_sequence<0, >
  15. template <std::size_t N, std::size_t ...Is>
  16. struct make_index_sequence : make_index_sequence <N - 1, N - 1, Is... > {};
  17.  
  18. template <std::size_t ... Is>
  19. struct make_index_sequence<0, Is...> : index_sequence<Is...> {};
  20.  
  21. // Generic IVisitor
  22. // Do: using MyIVisitor = IVisitorTs<Child1, Child2, ...>
  23. template <typename ... Ts> class IVisitorTs;
  24.  
  25. template <typename T, typename ... Ts>
  26. class IVisitorTs<T, Ts...> : public IVisitorTs<Ts...>
  27. {
  28. public:
  29. using tuple_type = std::tuple<T, Ts...>;
  30. using IVisitorTs<Ts...>::visit;
  31.  
  32. virtual void visit(const T& t) = 0;
  33. };
  34.  
  35. template <typename T> class IVisitorTs<T>
  36. {
  37. public:
  38. using tuple_type = std::tuple<T>;
  39.  
  40. virtual void visit(const T& t) = 0;
  41. };
  42.  
  43. namespace detail {
  44.  
  45. // retrieve the index of T in Ts...
  46. template <typename T, typename ... Ts> struct get_index;
  47.  
  48. template <typename T, typename ... Ts>
  49. struct get_index<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};
  50.  
  51. template <typename T, typename Tail, typename ... Ts>
  52. struct get_index<T, Tail, Ts...> :
  53. std::integral_constant < std::size_t, 1 + get_index<T, Ts...>::value > {};
  54.  
  55. // retrieve the index of T in Tuple<Ts...>
  56. template <typename T, typename Tuple> struct get_index_in_tuple;
  57.  
  58. template <typename T, template <typename...> class C, typename ... Ts>
  59. struct get_index_in_tuple<T, C<Ts...>> : get_index<T, Ts...> {};
  60.  
  61. // get element of a multiarray
  62. template <std::size_t I>
  63. struct multi_array_getter
  64. {
  65. template <typename T, std::size_t N>
  66. static constexpr auto get(const T& a, const std::array<std::size_t, N>& index)
  67. -> decltype(multi_array_getter<I - 1>::get(a[index[N - I]], index))
  68. {
  69. return multi_array_getter<I - 1>::get(a[index[N - I]], index);
  70. }
  71. };
  72.  
  73. template <>
  74. struct multi_array_getter<0>
  75. {
  76. template <typename T, std::size_t N>
  77. static constexpr auto get(const T& a, const std::array<std::size_t, N>& index)
  78. -> decltype(a)
  79. {
  80. return a;
  81. }
  82. };
  83.  
  84. // Provide an implementation of visitor
  85. // by forwarding to C implementation (which may be non virtual)
  86. template <typename IVisitor, typename C, typename...Ts> struct IVisitorImpl;
  87.  
  88. template <typename IVisitor, typename C, typename T, typename...Ts>
  89. struct IVisitorImpl<IVisitor, C, T, Ts...> : IVisitorImpl<IVisitor, C, Ts...>
  90. {
  91. virtual void visit(const T& t) override { C::visit(t); }
  92. };
  93.  
  94. template <typename IVisitor, typename C, typename T>
  95. struct IVisitorImpl<IVisitor, C, T> : IVisitor, C
  96. {
  97. virtual void visit(const T& t) override { C::visit(t); }
  98. };
  99.  
  100. // helper to expand child type to IVisitorImpl
  101. template <typename IVisitor, typename C>
  102. struct IVisitorImplType;
  103.  
  104. template <typename ... Ts, typename C>
  105. struct IVisitorImplType<IVisitorTs<Ts...>, C>
  106. {
  107. using type = IVisitorImpl<IVisitorTs<Ts...>, C, Ts...>;
  108. };
  109.  
  110. // Create an multi array of pointer of function
  111. // (with all combinaisons of overload).
  112. template <typename Ret, typename F, typename Arg>
  113. class GetAllOverload
  114. {
  115. private:
  116. template <typename...Ts>
  117. struct Functor
  118. {
  119. // function which will be in array.
  120. static Ret call(F&f, const Arg& arg)
  121. {
  122. return call_helper(f, arg, make_index_sequence<sizeof...(Ts)>());
  123. }
  124. private:
  125. // The final dispatched function
  126. template <std::size_t ... Is>
  127. static Ret call_helper(F&f, const Arg& arg, index_sequence<Is...>)
  128. {
  129. using RetTuple = std::tuple<Ts&...>;
  130. // static cast is suffisant if arg is the abstract type
  131. // when given arg is concrete type, reinterpret_cast is required.
  132. // TODO: build a smaller table with only possible value to avoid that
  133. return f(reinterpret_cast<typename std::tuple_element<Is, RetTuple>::type>(std::get<Is>(arg))...);
  134. }
  135. };
  136.  
  137. // helper class to create the multi array of function pointer
  138. template <std::size_t N, typename Tuple, typename...Ts>
  139. struct Builder;
  140.  
  141. template <typename...Ts, typename...Ts2>
  142. struct Builder<1, std::tuple<Ts...>, Ts2...>
  143. {
  144. using RetType = std::array<Ret (*)(F&, const Arg&), sizeof...(Ts)>;
  145.  
  146. static constexpr RetType build()
  147. {
  148. return RetType{ &Functor<Ts2..., Ts>::call... };
  149. }
  150. };
  151.  
  152. template <std::size_t N, typename ...Ts, typename...Ts2>
  153. struct Builder<N, std::tuple<Ts...>, Ts2...>
  154. {
  155. template <typename T>
  156. using RecType = Builder<N - 1, std::tuple<Ts...>, Ts2..., T>;
  157. using T0 = typename std::tuple_element<0, std::tuple<Ts...>>::type;
  158. using RetType = std::array<decltype(RecType<T0>::build()), sizeof...(Ts)>;
  159.  
  160. static constexpr RetType build() {
  161. return RetType{ RecType<Ts>::build()... };
  162. }
  163. };
  164.  
  165. public:
  166. template <std::size_t N, typename VisitorTuple>
  167. static constexpr auto get()
  168. -> decltype(Builder<N, VisitorTuple>::build())
  169. {
  170. return Builder<N, VisitorTuple>::build();
  171. }
  172. };
  173.  
  174. template <typename Ret, typename IVisitor, typename F, std::size_t N>
  175. class dispatcher
  176. {
  177. private:
  178. std::array<std::size_t, N> index;
  179.  
  180. struct visitorCallImpl
  181. {
  182. template <typename T>
  183. void visit(const T&) const
  184. {
  185. *index = get_index_in_tuple<T, IVisitor>::value;
  186. }
  187.  
  188. void setIndexPtr(std::size_t& index) { this->index = &index; }
  189. private:
  190. std::size_t* index = nullptr;
  191. };
  192.  
  193. template <std::size_t I, typename Tuple>
  194. void set_index(const Tuple&t)
  195. {
  196. using VisitorType = typename IVisitorImplType<IVisitor, visitorCallImpl>::type;
  197. VisitorType visitor;
  198. visitor.setIndexPtr(index[I]);
  199.  
  200. std::get<I>(t).accept(visitor);
  201. }
  202. public:
  203. template <typename Tuple, std::size_t ... Is>
  204. Ret operator () (F&& f, const Tuple&t, index_sequence<Is...>)
  205. {
  206. const int dummy[] = {(set_index<Is>(t), 0)...};
  207. static_cast<void>(dummy); // silent the warning unused varaible
  208. constexpr auto a = GetAllOverload<Ret, F&&, Tuple>::
  209. template get<sizeof...(Is), typename IVisitor::tuple_type>();
  210. auto func = multi_array_getter<N>::get(a, index);
  211. return (*func)(f, t);
  212. }
  213. };
  214.  
  215. } // namespace detail
  216.  
  217. template <typename Ret, typename Visitor, typename F, typename ... Ts>
  218. Ret dispatch(F&& f, Ts&...args)
  219. {
  220. constexpr std::size_t size = sizeof...(Ts);
  221. detail::dispatcher<Ret, Visitor, F&&, size> d;
  222. return d(std::forward<F>(f), std::tie(args...), make_index_sequence<size>());
  223. }
  224.  
  225. #endif // multiple dispatch
  226.  
  227. #if 1 // multiple dispatch usage
  228. struct Square;
  229. struct Rect;
  230. struct Circle;
  231.  
  232. using IShapeVisitor = IVisitorTs<Square, Rect, Circle>;
  233.  
  234. struct IShape {
  235. virtual ~IShape() = default;
  236. virtual void accept(IShapeVisitor&) const = 0;
  237. };
  238. struct Rect : IShape {
  239. virtual void accept(IShapeVisitor& v) const override { v.visit(*this); }
  240. };
  241.  
  242. struct Square : Rect {
  243. virtual void accept(IShapeVisitor& v) const override { v.visit(*this); }
  244. };
  245. struct Circle : IShape {
  246. virtual void accept(IShapeVisitor& v) const override { v.visit(*this); }
  247. };
  248.  
  249. class ShapePrinter : public IShapeVisitor
  250. {
  251. public:
  252. void visit(const Rect& s) override { std::cout << "Rect"; }
  253. void visit(const Square& s) override { std::cout << "Square"; }
  254. void visit(const Circle& s) override { std::cout << "Circle"; }
  255. };
  256.  
  257. struct IsEqual
  258. {
  259. bool operator() (IShape& s1, IShape& s2) const
  260. {
  261. ShapePrinter printer;
  262. s1.accept(printer);
  263. std::cout << " != ";
  264. s2.accept(printer);
  265. std::cout << std::endl;
  266. return false;
  267. }
  268.  
  269. template <typename S>
  270. bool operator() (S& s1, S& s2) const
  271. {
  272. ShapePrinter printer;
  273. s1.accept(printer);
  274. std::cout << " == ";
  275. s2.accept(printer);
  276. std::cout << std::endl;
  277. return true;
  278. }
  279. };
  280.  
  281. int main(int argc, char *argv[])
  282. {
  283. Rect rect;
  284. Square sq;
  285. Circle c;
  286. IShape* shapes[] = { &rect, &sq, &c };
  287.  
  288. for (auto shape1 : shapes) {
  289. for (auto shape2 : shapes) {
  290. dispatch<bool, IShapeVisitor>(IsEqual(), *shape1, *shape2);
  291. }
  292. }
  293. return 0;
  294. }
  295.  
  296. #endif // multiple dispatch usage
  297.  
Success #stdin #stdout 0s 3300KB
stdin
Standard input is empty
stdout
Rect == Rect
Rect != Square
Rect != Circle
Square != Rect
Square == Square
Square != Circle
Circle != Rect
Circle != Square
Circle == Circle