fork download
  1. #include <iostream>
  2. #include <functional>
  3.  
  4. template <typename T> struct TagTraits;
  5.  
  6. // Generic implementation of A based on TagTraits.
  7. class A {
  8.  
  9. template <typename Tag, typename... Args>
  10. class Execute {
  11. const A* a;
  12. public:
  13. Execute (const A* a_) : a(a_) {}
  14. typename TagTraits<Tag>::return_type operator()(Args&&... args) const
  15. {
  16. return (a->*(TagTraits<Tag>::get_funtion_ptr()))(std::forward<Args>(args)...);
  17. }
  18. };
  19.  
  20. public:
  21.  
  22. virtual int foo (int) const = 0;
  23. virtual void bar (char, double) const = 0;
  24.  
  25. template <typename Tag, typename... Args>
  26. typename TagTraits<Tag>::return_type execute(Args&&... args) const
  27. {
  28. return Execute<Tag, Args...>(this)(std::forward<Args>(args)...);
  29. }
  30. };
  31. // tag for foo and the corresponding TagTraits
  32. struct foo_tag {};
  33.  
  34. template <> struct TagTraits<foo_tag>
  35. {
  36. using return_type = int;
  37. static int (A::*get_funtion_ptr())(int) const { return &A::foo;}
  38. };
  39. // tag for bar and the corresponding TagTraits
  40. struct bar_tag {};
  41.  
  42. template <> struct TagTraits<bar_tag>
  43. {
  44. using return_type = void;
  45. static decltype(&A::bar) get_funtion_ptr(){ return &A::bar;}
  46. };
  47. // Derived classes of A.
  48.  
  49. class B : public A {
  50. virtual int foo (int) const {std::cout << "B::foo() called.\n"; return 3;}
  51. virtual void bar (char, double) const {std::cout << "B::bar() called.\n";}
  52. };
  53.  
  54. class C : public B {
  55. virtual int foo (int) const {std::cout << "C::foo() called.\n"; return 8;}
  56. virtual void bar (char, double) const {std::cout << "C::bar() called.\n";}
  57. };
  58. // Test B
  59. void test_B()
  60. {
  61. A* aPtr = new B;
  62.  
  63. int n = aPtr->foo(5); // B::foo() called.
  64. aPtr->bar(3, 'c'); // B::bar() called.
  65.  
  66. n = aPtr->execute<foo_tag>(5); // B::foo() called.
  67. aPtr->execute<bar_tag>(3, 'c'); // B::bar() called.
  68. }
  69.  
  70. // Test C
  71. void test_C()
  72. {
  73. A* aPtr = new C;
  74.  
  75. int n = aPtr->foo(5); // C::foo() called.
  76. aPtr->bar(3, 'c'); // C::bar() called.
  77.  
  78. n = aPtr->execute<foo_tag>(5); // C::foo() called.
  79. aPtr->execute<bar_tag>(3, 'c'); // C::bar() called.
  80. }
  81.  
  82. int main()
  83. {
  84. test_B();
  85. test_C();
  86. }
  87.  
Success #stdin #stdout 0s 3412KB
stdin
Standard input is empty
stdout
B::foo() called.
B::bar() called.
B::foo() called.
B::bar() called.
C::foo() called.
C::bar() called.
C::foo() called.
C::bar() called.