fork(2) download
  1. #include <type_traits>
  2. #include <vector>
  3.  
  4. namespace aux {
  5. template<typename, typename>
  6. class accumulator;
  7. }
  8.  
  9. template<typename>
  10. class signal;
  11.  
  12. template<typename R, typename... Args>
  13. class signal<R(Args...)>
  14. {
  15. public:
  16. template<typename Slot>
  17. void bind(Slot slot);
  18.  
  19. template<typename Accum>
  20. typename aux::accumulator<R, Accum>::result_type
  21. emit(Accum f, Args... args);
  22.  
  23. private:
  24. struct erased_slot;
  25.  
  26. std::vector<erased_slot> slots_;
  27. };
  28.  
  29. // emits the signal without accumulating anything.
  30. template<typename R, typename... Args>
  31. void emit(signal<R(Args...)>& sig, Args... args);
  32.  
  33. #include <memory>
  34. #include <utility>
  35.  
  36. namespace aux {
  37.  
  38. template<typename R, typename Accum>
  39. class accumulator
  40. {
  41. public:
  42. using result_type = typename std::result_of<Accum(R, R)>::type;
  43.  
  44. public:
  45. explicit accumulator(Accum accum) : state_(), accum_(std::move(accum)) {}
  46.  
  47. public:
  48. template<typename F, typename... Args>
  49. void step(F&& f, Args&&... args)
  50. {
  51. state_ = accum_(state_,
  52. std::forward<F>(f)(std::forward<Args>(args)...));
  53. }
  54.  
  55. result_type const& get_state() const&
  56. {
  57. return state_;
  58. }
  59.  
  60. result_type&& get_state() &&
  61. {
  62. return std::move(state_);
  63. }
  64.  
  65. private:
  66. result_type state_;
  67. Accum accum_;
  68. };
  69.  
  70. template<typename Accum>
  71. class accumulator<void, Accum>
  72. {
  73. public:
  74. using result_type = typename std::result_of<Accum()>::type;
  75.  
  76. public:
  77. explicit accumulator(Accum accum) : state_(), accum_(std::move(accum)) {}
  78.  
  79. public:
  80. template<typename F, typename... Args>
  81. void step(F&& f, Args&&... args)
  82. {
  83. std::forward<F>(f)(std::forward<Args>(args)...);
  84. state_ = accum_();
  85. }
  86.  
  87. result_type const& get_state() const&
  88. {
  89. return state_;
  90. }
  91.  
  92. result_type&& get_state() &&
  93. {
  94. return std::move(state_);
  95. }
  96.  
  97. private:
  98. result_type state_;
  99. Accum accum_;
  100. };
  101.  
  102. } // namespace aux-
  103.  
  104. template<typename R, typename... Args>
  105. struct signal<R(Args...)>::erased_slot
  106. {
  107. public:
  108. template<typename Slot>
  109. explicit erased_slot(Slot slot)
  110. : slot_(new model<Slot>(std::move(slot)))
  111. {
  112. }
  113.  
  114. erased_slot(erased_slot const& x) : slot_(x.slot_->clone()) { }
  115. erased_slot& operator=(erased_slot const& x)
  116. {
  117. slot_.reset(x.slot_->clone());
  118. return *this;
  119. }
  120.  
  121. erased_slot(erased_slot&& x) = default;
  122. erased_slot& operator=(erased_slot&& x) = default;
  123.  
  124. public:
  125. R operator()(Args... args)
  126. {
  127. return (*slot_)(std::forward<Args>(args)...);
  128. }
  129.  
  130. private:
  131. struct concept
  132. {
  133. virtual R operator()(Args... args) = 0;
  134. virtual concept* clone() const = 0;
  135. };
  136.  
  137. template<typename Slot>
  138. struct model final : public concept
  139. {
  140. Slot slot;
  141.  
  142. explicit model(Slot slot) : slot(std::move(slot)) { }
  143.  
  144. R operator()(Args... args) override
  145. {
  146. return slot(std::forward<Args>(args)...);
  147. }
  148.  
  149. model* clone() const override { return new model(*this); }
  150. };
  151.  
  152. std::unique_ptr<concept> slot_;
  153. };
  154.  
  155. template<typename R, typename... Args>
  156. template<typename Slot>
  157. void signal<R(Args...)>::bind(Slot slot)
  158. {
  159. slots_.emplace_back(std::move(slot));
  160. }
  161.  
  162. template<typename R, typename... Args>
  163. template<class Accum>
  164. typename aux::accumulator<R, Accum>::result_type
  165. signal<R(Args...)>::emit(Accum f, Args... args)
  166. {
  167. aux::accumulator<R, Accum> accum(std::move(f));
  168. for (auto& i : slots_) {
  169. accum.step(i, args...);
  170. }
  171. return std::move(accum).get_state();
  172. }
  173.  
  174. namespace aux {
  175.  
  176. struct do_nothing
  177. {
  178. template<typename... Args>
  179. int operator()(Args const&...) { return 0; }
  180. };
  181.  
  182. } // namespace aux
  183.  
  184. template<typename R, typename... Args>
  185. void emit(signal<R(Args...)>& sig, Args... args)
  186. {
  187. sig.emit(aux::do_nothing(), std::forward<Args>(args)...);
  188. }
  189.  
  190. #include <functional>
  191. #include <iostream>
  192.  
  193. int main()
  194. {
  195. signal<int()> sig;
  196. sig.bind([]() -> int { std::cout << "Hello, "; return 1; });
  197. sig.bind([]() -> int { std::cout << "world!\n"; return 2; });
  198. emit(sig);
  199. std::cout << sig.emit(std::plus<int>()) << '\n';
  200.  
  201. signal<void(int, int)> sig2;
  202. sig2.bind([](int const x, int const y) { std::cout << (x*y) << '\n'; });
  203. sig2.bind([](int const x, int const y) { std::cout << (x+y) << '\n'; });
  204. emit(sig2, 10, 2);
  205.  
  206. signal<std::string()> sig3;
  207. sig3.bind([]{ return "Stack"; });
  208. sig3.bind([]{ return "Overflow"; });
  209. sig3.bind([]{ return " C++\n"; });
  210. std::cout << sig3.emit(std::plus<std::string>()) << '\n';
  211. }
  212.  
Success #stdin #stdout 0s 3436KB
stdin
Standard input is empty
stdout
Hello, world!
Hello, world!
3
20
12
StackOverflow C++