fork(1) download
  1. // Generic, type-safe delegates.
  2. // (updated from blog.molecular-matters)
  3.  
  4. #include <iostream>
  5.  
  6. template<typename>
  7. struct Delegate {};
  8.  
  9. template<typename R, typename... Args>
  10. struct Delegate<R(Args...)>
  11. {
  12. Delegate()
  13. : m_stub{nullptr, nullptr}
  14. {}
  15.  
  16. template<R (*Function)(Args...)>
  17. void bind(void)
  18. {
  19. m_stub = {nullptr, s_function_stub<Function>};
  20. }
  21.  
  22. template<typename T, R (T::*Function)(Args...)>
  23. void bind(T* instance)
  24. {
  25. m_stub = {instance, s_classmethod_stub<T, Function>};
  26. }
  27.  
  28. R invoke(Args&&... args) const
  29. {
  30. if (!m_stub.second)
  31. throw std::runtime_error("Cannot invoke unbound delegate.");
  32. return m_stub.second(m_stub.first, std::forward<Args>(args)...);
  33. }
  34.  
  35. private:
  36. std::pair<void*, R (*)(void*, Args&&...)> m_stub;
  37.  
  38. template<R (*Function)(Args...)>
  39. static R s_function_stub(void*, Args&&... args)
  40. {
  41. return (Function)(std::forward<Args>(args)...);
  42. }
  43.  
  44. template<typename T, R (T::*Function)(Args...)>
  45. static R s_classmethod_stub(void* instance, Args&&... args)
  46. {
  47. return (static_cast<T*>(instance)->*Function)(std::forward<Args>(args)...);
  48. }
  49. };
  50.  
  51. // Main.
  52.  
  53. void function()
  54. {
  55. std::cout << __PRETTY_FUNCTION__ << "\n";
  56. }
  57.  
  58. struct Class
  59. {
  60. bool classmethod(int i, double x)
  61. {
  62. std::cout << __PRETTY_FUNCTION__ << " -> ";
  63. std::cout << i << ", " << x << "\n";
  64. return true;
  65. }
  66. };
  67.  
  68. int main()
  69. {
  70. Delegate<void()> a;
  71. a.bind<function>();
  72. a.invoke();
  73. Class instance;
  74. Delegate<bool(int, double)> b;
  75. b.bind<Class, &Class::classmethod>(&instance);
  76. if (b.invoke(1, 2.3))
  77. std::cout << "true";
  78. }
Success #stdin #stdout 0s 5316KB
stdin
Standard input is empty
stdout
void function()
bool Class::classmethod(int, double) -> 1, 2.3
true