fork download
  1. #include <cstdint>
  2. #include <array>
  3. #include <iostream>
  4. #include <tuple>
  5. #include <type_traits>
  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 A;
  229. struct B;
  230. struct C;
  231. struct D;
  232.  
  233.  
  234. using IAVisitor = IVisitorTs<A, B, C, D>;
  235.  
  236. struct A {
  237. virtual ~A() = default;
  238. virtual void accept(IAVisitor& v) const { v.visit(*this); }
  239. };
  240. struct B : A {
  241. virtual void accept(IAVisitor& v) const override { v.visit(*this); }
  242. };
  243.  
  244. struct C : A {
  245. virtual void accept(IAVisitor& v) const override { v.visit(*this); }
  246. };
  247. struct D : A {
  248. virtual void accept(IAVisitor& v) const override { v.visit(*this); }
  249. };
  250.  
  251. class Object {
  252. public:
  253. virtual double foo (A*, A*) { std::cout << "Object::foo A,A\n"; return 3.14; }
  254. virtual double foo (B*, B*) { std::cout << "Object::foo B,B\n"; return 3.14; }
  255. virtual double foo (B*, C*) { std::cout << "Object::foo B,C\n"; return 3.14; }
  256. virtual double foo (C*, B*) { std::cout << "Object::foo C,B\n"; return 3.14; }
  257. virtual double foo (C*, C*) { std::cout << "Object::foo C,C\n"; return 3.14; }
  258. virtual char foo (A*, A*, A*) const { std::cout << "Object::foo A,A,A\n"; return '&'; }
  259. virtual char foo (C*, B*, D*) const { std::cout << "Object::foo C,B,D\n"; return '!'; } // Overload of foo with three arguments.
  260. virtual void bar (A*, A*, A*) const { std::cout << "Object::bar A,A,A\n"; }
  261. virtual void bar (B*, B*, B*) const { std::cout << "Object::bar B,B,B\n"; }
  262. virtual void bar (B*, C*, B*) const { std::cout << "Object::bar B,C,B\n"; }
  263. virtual void bar (B*, C*, C*) const { std::cout << "Object::bar B,C,C\n"; }
  264. virtual void bar (B*, C*, D*) const { std::cout << "Object::bar B,C,D\n"; }
  265. virtual void bar (C*, B*, D*) const { std::cout << "Object::bar C,B,D\n"; }
  266. virtual void bar (C*, C*, C*) const { std::cout << "Object::bar C,C,C\n"; }
  267. virtual void bar (D*, B*, C*) const { std::cout << "Object::bar D,B,C\n"; }
  268. double fooMultipleDispatch (A*, A*);
  269. char fooMultipleDispatch (A*, A*, A*);
  270. };
  271.  
  272. class FooDispatcher
  273. {
  274. public:
  275. explicit FooDispatcher(Object& object) : object(object) {}
  276.  
  277. template <typename T1, typename T2>
  278. double operator() (T1& a1, T2& a2) const
  279. {
  280. return object.foo(&a1, &a2);
  281. }
  282.  
  283. template <typename T1, typename T2, typename T3>
  284. char operator() (T1& a1, T2& a2, T3& a3) const
  285. {
  286. return object.foo(&a1, &a2, &a3);
  287. }
  288. private:
  289. Object& object;
  290. };
  291.  
  292. double Object::fooMultipleDispatch (A* a1, A* a2)
  293. {
  294. return dispatch<double, IAVisitor>(FooDispatcher(*this), *a1, *a2);
  295. }
  296. char Object::fooMultipleDispatch (A* a1, A* a2, A* a3)
  297. {
  298. return dispatch<char, IAVisitor>(FooDispatcher(*this), *a1, *a2, *a3);
  299. }
  300.  
  301.  
  302. int main() {
  303. A a_a;
  304. B a_b;
  305. C a_c;
  306. D a_d;
  307. A* a[] = {&a_b, &a_c, &a_d, &a_a};
  308. Object object;
  309.  
  310. double d = object.foo (a[0], a[1]); // Object::foo A,A (no multiple dispatch)
  311. d = object.fooMultipleDispatch (a[0], a[1]); // Object::foo B,C
  312. std::cout << "d = " << d << std::endl; // 3.14
  313.  
  314. object.fooMultipleDispatch (a[0], a[3]); // B,A -> so best match is Object::foo A,A
  315.  
  316. const char k = object.fooMultipleDispatch (a[1], a[0], a[2]); // Object::foo C,B,D
  317. std::cout << "k = " << k << std::endl; // !
  318. }
  319.  
  320. #endif // multiple dispatch usage
  321.  
Success #stdin #stdout 0s 3160KB
stdin
Standard input is empty
stdout
Object::foo A,A
Object::foo B,C
d = 3.14
Object::foo A,A
Object::foo C,B,D
k = !