[libsigcplusplus] signal: Allow sigc::signal<R(Args...)> declaration, like std::function.
- From: Murray Cumming <murrayc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsigcplusplus] signal: Allow sigc::signal<R(Args...)> declaration, like std::function.
- Date: Fri, 11 Mar 2016 10:13:23 +0000 (UTC)
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]