fork download
  1. #include <type_traits>
  2. #include <utility>
  3. #include <typeinfo>
  4. #include <cassert>
  5. #include <stdexcept>
  6.  
  7. template<std::size_t index, class...Ts> struct get_variadic_by_index;
  8. template<std::size_t index, class First, class...Rests> struct get_variadic_by_index<index,First,Rests...> : public get_variadic_by_index<index-1,Rests...> {};
  9. template<class First, class...Rests> struct get_variadic_by_index<0,First,Rests...> {typedef First type;};
  10.  
  11.  
  12. template<class func_type, class LBase, class RBase, class LTypes, class RTypes> class double_dispatch;
  13. template<class func_type, class LBase, class RBase, class...Ls, class...Rs>
  14. class double_dispatch<func_type, LBase, RBase, std::tuple<Ls...>,std::tuple<Rs...>>
  15. {
  16. typedef decltype(std::declval<func_type>()(
  17. std::declval<typename get_variadic_by_index<0,Ls...>::type*>(),
  18. std::declval<typename get_variadic_by_index<0,Rs...>::type*>()
  19. )) return_type;
  20.  
  21. template<int LI, int RI>
  22. return_type call(LBase* l, RBase* r)
  23. {
  24. return func(
  25. static_cast<typename get_variadic_by_index<LI,Ls...>::type*>(l),
  26. static_cast<typename get_variadic_by_index<RI,Rs...>::type*>(r)
  27. );
  28. }
  29.  
  30. template<int LI>
  31. return_type iter_right_types(LBase*, RBase*, const std::type_info&, std::integral_constant<int,sizeof...(Rs)>)
  32. {assert("typeid(r) is not in tuple list"); throw std::bad_cast();}
  33.  
  34. template<int LI, int RI>
  35. return_type iter_right_types(LBase* l, RBase* r, const std::type_info& righttype, std::integral_constant<int,RI>)
  36. {
  37. if (righttype==typeid(typename get_variadic_by_index<RI,Rs...>::type))
  38. return call<LI,RI>(l, r);
  39. else
  40. return iter_right_types<LI>(l, r, righttype, std::integral_constant<int,RI+1>());
  41. }
  42.  
  43. return_type iter_left_types(LBase*, RBase*, const std::type_info&, std::integral_constant<int,sizeof...(Ls)>)
  44. {assert("typeid(l) is not in tuple list"); throw std::bad_cast();}
  45.  
  46. template<int LI>
  47. return_type iter_left_types(LBase* l, RBase* r, const std::type_info& lefttype, std::integral_constant<int,LI>)
  48. {
  49. if (lefttype==typeid(typename get_variadic_by_index<LI,Ls...>::type))
  50. return iter_right_types<LI>(l, r, typeid(*r), std::integral_constant<int,0>());
  51. else
  52. return iter_left_types(l, r, lefttype, std::integral_constant<int,LI+1>());
  53. }
  54. func_type func;
  55. public:
  56. explicit double_dispatch(func_type func) : func(func) {}
  57.  
  58. return_type operator()(LBase* l, RBase* r)
  59. {return iter_left_types(l, r, typeid(*l), std::integral_constant<int,0>());}
  60.  
  61. return_type dispatch(LBase* l, RBase* r)
  62. {return iter_left_types(l, r, typeid(*l), std::integral_constant<int,0>());}
  63. };
  64. #define DOUBLE_DISPATCHER(FUNC) \
  65. struct {\
  66.   template<class L,class R> \
  67.   auto operator()(L&& l, R&& r) \
  68.   ->decltype(FUNC(std::forward<L>(l),std::forward<R>(r))) \
  69.   {return FUNC(std::forward<L>(l),std::forward<R>(r));} \
  70. }
  71.  
  72.  
  73.  
  74. #include <iostream>
  75. struct Loud {
  76. Loud() {std::cerr << "LOUD: default ctor\n";}
  77. Loud(const Loud&) {std::cerr << "LOUD: copy ctor\n";}
  78. Loud(Loud&&) {std::cerr << "LOUD: move ctor\n";}
  79. ~Loud() {std::cerr << "LOUD: dtor\n";}
  80. Loud& operator=(const Loud&) {std::cerr << "LOUD: copy assign\n"; return *this;}
  81. Loud& operator=(Loud&&) {std::cerr << "LOUD: move assign\n"; return *this;}
  82. };
  83. struct Letter {
  84. virtual ~Letter() {}
  85. };
  86. struct A : public Letter {};
  87. struct B : public Letter {};
  88. struct C : public Letter {};
  89. struct Number {
  90. virtual ~Number() {}
  91. };
  92. struct One : public Number {};
  93. struct Two : public Number {};
  94. struct Three : public Number {};
  95.  
  96. Loud print(const A*,const One*) {std::cerr << "A1\n"; return {};}
  97. Loud print(const A*,const Two*) {std::cerr << "A2\n"; return {};}
  98. Loud print(const A*,const Three*) {std::cerr << "A3\n"; return {};}
  99. Loud print(const B*,const One*) {std::cerr << "B1\n"; return {};}
  100. Loud print(const B*,const Two*) {std::cerr << "B2\n"; return {};}
  101. Loud print(const B*,const Three*) {std::cerr << "B3\n"; return {};}
  102. Loud print(const C*,const One*) {std::cerr << "C1\n"; return {};}
  103. Loud print(const C*,const Two*) {std::cerr << "C2\n"; return {};}
  104. Loud print(const C*,const Three*) {std::cerr << "C3\n"; return {};}
  105. DOUBLE_DISPATCHER(print) printdispatch;
  106. double_dispatch<decltype(printdispatch), const Letter, const Number,
  107. std::tuple<const A,const B,const C>,
  108. std::tuple<const One,const Two,const Three>>
  109. d_dispatcher(printdispatch);
  110.  
  111. int main()
  112. {
  113. const Letter& a = A{};
  114. const Letter& b = B{};
  115. const Letter& c = C{};
  116. const Number& on = One{};
  117. const Number& tw = Two{};
  118. const Number& th = Three{};
  119.  
  120. d_dispatcher(&a,&on);
  121. d_dispatcher(&a,&tw);
  122. d_dispatcher(&a,&th);
  123. d_dispatcher(&b,&on);
  124. d_dispatcher(&b,&tw);
  125. d_dispatcher(&b,&th);
  126. d_dispatcher(&c,&on);
  127. d_dispatcher(&c,&tw);
  128. d_dispatcher(&c,&th);
  129.  
  130. return 0;
  131. }
Success #stdin #stdout #stderr 0s 3296KB
stdin
Standard input is empty
stdout

Standard output is empty

stderr
A1
LOUD: default ctor
LOUD: dtor
A2
LOUD: default ctor
LOUD: dtor
A3
LOUD: default ctor
LOUD: dtor
B1
LOUD: default ctor
LOUD: dtor
B2
LOUD: default ctor
LOUD: dtor
B3
LOUD: default ctor
LOUD: dtor
C1
LOUD: default ctor
LOUD: dtor
C2
LOUD: default ctor
LOUD: dtor
C3
LOUD: default ctor
LOUD: dtor