CallbackTest_03.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // callback5.cpp - Template Functor Callback (Rich Hickey)
  2. // Situation: A "Caller" class allows another class "Callee"
  3. // to connect to it via callback. How to implement this?
  4. // This version uses Rich Hickey's template functor approach.
  5. // Advantages:
  6. // - Simple.
  7. // Disadvantages:
  8. // - CBFunctor1wRet<int, int> is a bit clunky. Especially when compared
  9. // to std::function<int(int)>.
  10. // Overall, Rich Hickey's still seems better than even the new std::function
  11. // and lambda approach available in C++11. Key differences:
  12. // typedef std::function<int(int)> CallbackFunction;
  13. // typedef CBFunctor1wRet<int, int> CallbackFunction;
  14. // Ok, the std::function typedef is much more elegant than the clunky
  15. // CBFunctor1wRet.
  16. // caller.connectCallback([&callee](int i) { return callee.foo(i); });
  17. // caller.connectCallback(makeFunctor(callee, &Callee::foo));
  18. // makeFunctor() wins over the lambda function, though. The lambda function
  19. // is far more impenetrable than CBFunctor1wRet is clunky. So, I think
  20. // Rich Hickey's wins by a slim margin.
  21. // Hmmmm. If this is a functor... Can we combine the two? Maybe, but we
  22. // would need to experiment with a newer version of Rich Hickey's callback
  23. // that doesn't need the pointer argument to differentiate between versions
  24. // of makeFunctor. Need to find that for callback experiment #6.
  25. // (I use printf() because it is faster than cout << ...)
  26. #include <stdio.h>
  27. #include "Header.h"
  28. //------------------------------------------------------------------------
  29. // Callback function.
  30. typedef CBFunctor1wRet<int, int> CallbackFunction;
  31. //------------------------------------------------------------------------
  32. // "Caller" allows a callback to be connected. It will call that callback.
  33. class Caller
  34. {
  35. public:
  36. // Clients can connect their callback with this.
  37. void connectCallback(CallbackFunction cb)
  38. {
  39. m_cb = cb;
  40. }
  41. // Test the callback to make sure it works.
  42. void test()
  43. {
  44. printf("Caller::test() calling callback...\n");
  45. int i = m_cb(10);
  46. printf("Result (50): %d\n", i);
  47. }
  48. private:
  49. // The callback provided by the client via connectCallback().
  50. CallbackFunction m_cb;
  51. };
  52. //------------------------------------------------------------------------
  53. // "Callee" can provide a callback to Caller.
  54. class Callee
  55. {
  56. public:
  57. Callee(int i) : m_i(i) { }
  58. // The callback function that Caller will call.
  59. int callbackFunction(int i)
  60. {
  61. printf(" Callee::callbackFunction() inside callback\n");
  62. return m_i * i;
  63. }
  64. private:
  65. // To prove "this" is indeed valid within foo().
  66. int m_i;
  67. };
  68. //------------------------------------------------------------------------
  69. int main()
  70. {
  71. Caller caller;
  72. Callee callee(5);
  73. // Connect the callback. Like with the C-style function pointer and
  74. // static function, we use a lambda to get back into the object.
  75. caller.connectCallback(
  76. makeFunctor((CallbackFunction*)0, callee, &Callee::callbackFunction));
  77. // There are available newer versions of this that use "member
  78. // templates" and therefore don't need the first parameter to
  79. // makeFunctor() to figure out what's going on.
  80. // That gives:
  81. // caller.connectCallback(makeFunctor(callee, &Callee::foo));
  82. // Note how this is getting closer to the ultimate:
  83. // caller.connectCallback(callee.foo);
  84. // Test the callback
  85. caller.test();
  86. return 0;
  87. }