[libsigcplusplus] signal: Allow sigc::signal<R(Args...)> declaration, like std::function.



commit e399c4ebdb633d242e7086ceb2a548057cd5889b
Author: Murray Cumming <murrayc murrayc com>
Date:   Fri Mar 11 11:00:05 2016 +0100

    signal: Allow sigc::signal<R(Args...)> declaration, like std::function.
    
    By adding a template specialization that repeats the main
    template declaration, though it would be good to avoid the repetition.
    
    Bug #763393
    
     Please enter the commit message for your changes. Lines starting

 sigc++/signal.h           |  122 +++++++++++++++++++++++++++++++++++++++++++++
 tests/test_accumulated.cc |   23 +++++++++
 tests/test_signal.cc      |   11 ++++
 3 files changed, 156 insertions(+), 0 deletions(-)
---
diff --git a/sigc++/signal.h b/sigc++/signal.h
index 49ff16c..0961920 100644
--- a/sigc++/signal.h
+++ b/sigc++/signal.h
@@ -1088,6 +1088,128 @@ public:
 };
 
 
+/** signal can be used to connect() slots that are invoked
+ * during subsequent calls to emit(). Any functor or slot
+ * can be passed into connect(). It is converted into a slot
+ * implicitly.
+ *
+ * If you want to connect one signal to another, use make_slot()
+ * to retrieve a functor that emits the signal when invoked.
+ *
+ * Be careful if you directly pass one signal into the connect()
+ * method of another: a shallow copy of the signal is made and
+ * the signal's slots are not disconnected until both the signal
+ * and its clone are destroyed, which is probably not what you want!
+ *
+ * An STL-style list interface for the signal's list of slots
+ * can be retrieved with slots(). This interface supports
+ * iteration, insertion and removal of slots.
+ *
+ * The template arguments determine the function signature of
+ * the emit() function:
+ * - @e T_return The desired return type of the emit() function. * - @e T_arg Argument types used in the 
definition of emit().
+ *
+ * For instance, to declare a signal whose connected slot returns void and takes
+ * two parameters of bool and int:
+ * @code
+ * sigc::signal<void, bool, int> some_signal;
+ * @endcode
+ *
+ * Alternatively, you may use a syntax similar to that used by std::function<>:
+ * @code
+ * sigc::signal<void(bool, int)> some_signal;
+ * @endcode
+ *
+ * To specify an accumulator type the nested class signal::accumulated can be used.
+ *
+ * @par Example:
+ * @code
+ * void foo(int) {}
+ * sigc::signal<void, long> sig;
+ * sig.connect(sigc::ptr_fun(&foo));
+ * sig.emit(19);
+ * @endcode
+ *
+ * @ingroup signal
+ */
+template <class T_return, class... T_arg>
+class signal<T_return(T_arg...)>
+  : public signal_with_accumulator<T_return, void, T_arg...>
+{
+public:
+  using accumulator_type = void;
+
+  /** Like sigc::signal but the additional template parameter @e T_accumulator
+   * defines the accumulator type that should be used.
+   *
+   * An accumulator is a functor that uses a pair of special iterators
+   * to step through a list of slots and calculate a return value
+   * from the results of the slot invokations. The iterators' operator*()
+   * executes the slot. The return value is buffered, so that in an expression
+   * like @code a = (*i) * (*i); @endcode the slot is executed only once.
+   * The accumulator must define its return value as @p result_type.
+   *
+   * @par Example 1:
+   * This accumulator calculates the arithmetic mean value:
+   * @code
+   * struct arithmetic_mean_accumulator
+   * {
+   *   using result_type = double;
+   *   template<typename T_iterator>
+   *   result_type operator()(T_iterator first, T_iterator last) const
+   *   {
+   *     result_type value_ = 0;
+   *     int n_ = 0;
+   *     for (; first != last; ++first, ++n_)
+   *       value_ += *first;
+   *     return value_ / n_;
+   *   }
+   * };
+   * @endcode
+   *
+   * @par Example 2:
+   * This accumulator stops signal emission when a slot returns zero:
+   * @code
+   * struct interruptable_accumulator
+   * {
+   *   using result_type = bool;
+   *   template<typename T_iterator>
+   *   result_type operator()(T_iterator first, T_iterator last) const
+   *   {
+   *     for (; first != last; ++first, ++n_)
+   *       if (!*first) return false;
+   *     return true;
+   *   }
+   * };
+   * @endcode
+   *
+   * @ingroup signal
+   */
+  template <class T_accumulator>
+  using accumulated = typename signal<T_return, T_arg...>::template accumulated<T_accumulator>;
+
+  signal() {}
+
+  signal(const signal& src)
+    : signal_with_accumulator<T_return, accumulator_type, T_arg...>(src) {}
+
+  signal(signal&& src)
+    : signal_with_accumulator<T_return, accumulator_type, T_arg...>(std::move(src)) {}
+
+  signal& operator=(const signal& src)
+  {
+    signal_with_accumulator<T_return, accumulator_type, T_arg...>::operator=(src);
+    return *this;
+  }
+
+  signal& operator=(signal&& src)
+  {
+    signal_with_accumulator<T_return, accumulator_type, T_arg...>::operator=(std::move(src));
+    return *this;
+  }
+};
+
+
 
 } /* namespace sigc */
 
diff --git a/tests/test_accumulated.cc b/tests/test_accumulated.cc
index 9311131..600793b 100644
--- a/tests/test_accumulated.cc
+++ b/tests/test_accumulated.cc
@@ -129,6 +129,28 @@ void test_vector_accumulator()
     "foo: 10, A::foo: 46, bar: 12, Vector accumulator: Result (i=3): 10 46 12 ");
 }
 
+void test_mean_std_function_style_syntax()
+{
+  sigc::signal<int(int)>::accumulated<arithmetic_mean_accumulator> sig;
+
+  A a;
+  sig.connect(sigc::ptr_fun(&foo));
+  sig.connect(sigc::mem_fun(a, &A::foo));
+  sig.connect(sigc::ptr_fun(&bar));
+
+  double dres = sig(1);
+  result_stream << "Mean accumulator: Result (i=1): "
+                << std::fixed << std::setprecision(3) << dres;
+  util->check_result(result_stream,
+    "foo: 4, A::foo: 6, bar: 2, Mean accumulator: Result (i=1): 4.000");
+
+  dres = sig(11);
+  result_stream << "Mean accumulator: Plain Result (i=11): "
+                << std::fixed << std::setprecision(3) << dres;
+  util->check_result(result_stream,
+    "foo: 34, A::foo: 206, bar: 52, Mean accumulator: Plain Result (i=11): 97.333");
+}
+
 } // end anonymous namespace
 
 int main(int argc, char* argv[])
@@ -141,6 +163,7 @@ int main(int argc, char* argv[])
   test_empty_signal();
   test_mean();
   test_vector_accumulator();
+  test_mean_std_function_style_syntax();
 
   return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/tests/test_signal.cc b/tests/test_signal.cc
index 7172b29..3cd51a5 100644
--- a/tests/test_signal.cc
+++ b/tests/test_signal.cc
@@ -110,6 +110,16 @@ void test_make_slot()
   util->check_result(result_stream, "foo(int 3) bar(float 3) foo(int 3) ");
 }
 
+void test_std_function_style_syntax()
+{
+  sigc::signal<int(int)> sig;
+  sig.connect(sigc::ptr_fun(&foo));
+
+  sig(1);
+  util->check_result(result_stream, "foo(int 1) ");
+}
+
+
 } // end anonymous namespace
 
 int main(int argc, char* argv[])
@@ -124,6 +134,7 @@ int main(int argc, char* argv[])
   test_auto_disconnection();
   test_reference();
   test_make_slot();
+  test_std_function_style_syntax();
 
   return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]