fork(1) download
  1. #include <iostream>
  2.  
  3. class A { };
  4. class B { };
  5.  
  6. class Executor {
  7. public:
  8. // Callback base class including placeholders for operators that
  9. // are not overridden.
  10. class Callback {
  11. public:
  12. virtual ~Callback() { }
  13.  
  14. virtual void operator()(A const &) {
  15. std::cout << "Placeholder A" << std::endl;
  16. }
  17. virtual void operator()(B const &) {
  18. std::cout << "Placeholder B" << std::endl;
  19. }
  20. };
  21.  
  22. // Template method that can take a Callback directly, or it can
  23. // take a lambda and will wrap it as a Callback.
  24. template <typename T_Callback>
  25. void execute(T_Callback &&callback);
  26. private:
  27. // This method finds As and Bs to call the callback with.
  28. // It is not a template method and can be located in a source
  29. // (rather than header) file.
  30. void run(Callback &callback) {
  31. A a;
  32. B b;
  33. callback(a);
  34. callback(b);
  35. }
  36.  
  37. // Callback class for wrapping a lambda taking A.
  38. template <typename T_Callback>
  39. class CallbackFunctionA : public Callback {
  40. public:
  41. CallbackFunctionA(T_Callback &callback)
  42. : callback_(callback) { }
  43.  
  44. // Define operator taking A.
  45. virtual void operator()(A const &a) {
  46. callback_(a);
  47. }
  48. // Use other placeholder operators.
  49. using Callback::operator();
  50. private:
  51. T_Callback &callback_;
  52. };
  53.  
  54. // Callback class for wrapping a lambda taking B.
  55. template <typename T_Callback>
  56. class CallbackFunctionB : public Callback {
  57. public:
  58. CallbackFunctionB(T_Callback &callback)
  59. : callback_(callback) { }
  60.  
  61. // Define operator taking B.
  62. virtual void operator()(B const &b) {
  63. callback_(b);
  64. }
  65. // Use other placeholder operators.
  66. using Callback::operator();
  67. private:
  68. T_Callback &callback_;
  69. };
  70.  
  71. // Determine type in which to wrap T_Callback.
  72. template <typename T_Callback>
  73. class CallbackType {
  74. private:
  75. template <typename T>
  76. static CallbackFunctionA<T> testlambda(void (T::*op)(A const &) const);
  77. template <typename T>
  78. static CallbackFunctionB<T> testlambda(void (T::*op)(B const &) const);
  79.  
  80. template <typename T>
  81. static decltype(testlambda<T>(&T::operator())) testany(int);
  82. template <typename T>
  83. static T &testany(...);
  84. public:
  85. typedef decltype(testany<T_Callback>(0)) type;
  86. };
  87. };
  88.  
  89. template <typename T_Callback>
  90. void Executor::execute(T_Callback &&callback) {
  91. // Determine callback class to use and instantiate it.
  92. typename CallbackType<T_Callback>::type cb = callback;
  93. run(cb);
  94. }
  95.  
  96. int main() {
  97. Executor executor;
  98.  
  99. // Execute executor given a functor taking either A or B.
  100. struct : Executor::Callback {
  101. virtual void operator()(A const &) {
  102. std::cout << "Functor A" << std::endl;
  103. }
  104. virtual void operator()(B const &) {
  105. std::cout << "Functor B" << std::endl;
  106. }
  107. } callback;
  108. executor.execute(callback);
  109.  
  110. // Execute executor given a lambda taking an A.
  111. executor.execute(
  112. [](A const &) {
  113. std::cout << "Lambda A" << std::endl;
  114. }
  115. );
  116.  
  117. // Execute executor given a lambda taking a B.
  118. executor.execute(
  119. [](B const &) {
  120. std::cout << "Lambda B" << std::endl;
  121. }
  122. );
  123. }
  124.  
Success #stdin #stdout 0s 3344KB
stdin
Standard input is empty
stdout
Functor A
Functor B
Lambda A
Placeholder B
Placeholder A
Lambda B