summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjell Ahlstedt <kjell.ahlstedt@bredband.net>2013-02-26 09:29:34 +0100
committerKjell Ahlstedt <kjell.ahlstedt@bredband.net>2013-02-26 09:29:34 +0100
commitb0727f4e8cbb289d66b11fc29adf133f6c86847e (patch)
tree46191fbeb400c8fe00b36d632c14fd540eaca167
parent7c6ff314507bd0beb3b92ebf0a0f6258b67d7796 (diff)
downloadsigc++-b0727f4e8cbb289d66b11fc29adf133f6c86847e.tar.gz
Add track_obj() and test_track_obj.
* sigc++/.gitignore: Add adaptors/track_obj.h. * sigc++/adaptors/adaptors.h: Add sigc++/adaptors/track_obj.h. * sigc++/adaptors/lambda/macros/group.h.m4: * sigc++/adaptors/macros/adaptor_trait.h.m4: Mention track_obj() in the documentation. * sigc++/adaptors/macros/track_obj.h.m4: New file. * sigc++/filelist.am: Add track_obj.h.m4 and track_obj.h. * tests/.gitignore: * tests/Makefile.am: Add test_track_obj. * tests/test_cpp11_lambda.cc: Use track_obj() to test auto-disconnection. * tests/test_track_obj.cc: New test case. Bug #672555.
-rw-r--r--ChangeLog17
-rw-r--r--sigc++/.gitignore1
-rw-r--r--sigc++/adaptors/adaptors.h1
-rw-r--r--sigc++/adaptors/lambda/macros/group.h.m419
-rw-r--r--sigc++/adaptors/macros/adaptor_trait.h.m45
-rw-r--r--sigc++/adaptors/macros/track_obj.h.m4218
-rw-r--r--sigc++/filelist.am6
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/Makefile.am4
-rw-r--r--tests/test_cpp11_lambda.cc30
-rw-r--r--tests/test_track_obj.cc230
11 files changed, 498 insertions, 34 deletions
diff --git a/ChangeLog b/ChangeLog
index 4c75b9e..a572270 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2013-02-26 Kjell Ahlstedt <kjell.ahlstedt@bredband.net>
+
+ Add track_obj() and test_track_obj.
+
+ * sigc++/.gitignore: Add adaptors/track_obj.h.
+ * sigc++/adaptors/adaptors.h: Add sigc++/adaptors/track_obj.h.
+ * sigc++/adaptors/lambda/macros/group.h.m4:
+ * sigc++/adaptors/macros/adaptor_trait.h.m4: Mention track_obj() in the
+ documentation.
+ * sigc++/adaptors/macros/track_obj.h.m4: New file.
+ * sigc++/filelist.am: Add track_obj.h.m4 and track_obj.h.
+ * tests/.gitignore:
+ * tests/Makefile.am: Add test_track_obj.
+ * tests/test_cpp11_lambda.cc: Use track_obj() to test auto-disconnection.
+ * tests/test_track_obj.cc: New test case.
+ Bug #672555.
+
2013-01-07 Kjell Ahlstedt <kjell.ahlstedt@bredband.net>
Documentation: Fix many warnings from Doxygen.
diff --git a/sigc++/.gitignore b/sigc++/.gitignore
index 5930a6c..ff73c06 100644
--- a/sigc++/.gitignore
+++ b/sigc++/.gitignore
@@ -15,6 +15,7 @@
/adaptors/hide.h
/adaptors/retype.h
/adaptors/retype_return.h
+/adaptors/track_obj.h
/adaptors/lambda/base.h
/adaptors/lambda/group.h
/adaptors/lambda/lambda.cc
diff --git a/sigc++/adaptors/adaptors.h b/sigc++/adaptors/adaptors.h
index 950063b..ef484a4 100644
--- a/sigc++/adaptors/adaptors.h
+++ b/sigc++/adaptors/adaptors.h
@@ -27,6 +27,7 @@
#include <sigc++/adaptors/retype.h>
#include <sigc++/adaptors/compose.h>
#include <sigc++/adaptors/exception_catch.h>
+#include <sigc++/adaptors/track_obj.h>
#include <sigc++/adaptors/lambda/lambda.h>
#endif /* _SIGC_ADAPTOR_HPP_ */
diff --git a/sigc++/adaptors/lambda/macros/group.h.m4 b/sigc++/adaptors/lambda/macros/group.h.m4
index 1d4663c..f3b6cb8 100644
--- a/sigc++/adaptors/lambda/macros/group.h.m4
+++ b/sigc++/adaptors/lambda/macros/group.h.m4
@@ -169,6 +169,10 @@ __FIREWALL__
* by reference, a slot assigned to the group adaptor is cleared automatically
* when the object goes out of scope.
*
+ * If you bind an object of a sigc::trackable derived type to a C++11 lambda expression
+ * by reference, a slot assigned to the lambda expression is cleared automatically
+ * when the object goes out of scope only if you use sigc::track_obj().
+ *
* @par Example:
* @code
* struct bar : public sigc::trackable {} some_bar;
@@ -176,21 +180,10 @@ __FIREWALL__
* void foo(bar&);
* some_signal.connect(sigc::group(&foo,sigc::ref(some_bar)));
* // disconnected automatically if some_bar goes out of scope
- * @endcode
- *
- * std::bind() and C++11 lambda expressions fail here. If you store a
- * reference to a sigc::trackable derived object in a C++11 lambda expression,
- * and assign this expression to a slot or signal, it will not be disconnected
- * automatically when the object goes out of scope. The previous example can
- * still be rewritten without sigc::group().
- * @code
- * struct bar : public sigc::trackable {} some_bar;
- * sigc::signal<void> some_signal;
- * void foo(bar&);
- * some_signal.connect(sigc::bind(&foo, sigc::ref(some_bar)));
- * // disconnected automatically if some_bar goes out of scope
* some_signal.connect([[&some_bar]](){ foo(some_bar); }); //C++11
* // NOT disconnected automatically if some_bar goes out of scope
+ * some_signal.connect(sigc::track_obj([[&some_bar]](){ foo(some_bar); }, some_bar)); //C++11
+ * // disconnected automatically if some_bar goes out of scope
* @endcode
*
* @ingroup adaptors lambdas
diff --git a/sigc++/adaptors/macros/adaptor_trait.h.m4 b/sigc++/adaptors/macros/adaptor_trait.h.m4
index 2456904..7943a19 100644
--- a/sigc++/adaptors/macros/adaptor_trait.h.m4
+++ b/sigc++/adaptors/macros/adaptor_trait.h.m4
@@ -104,13 +104,14 @@ template <class T_functor> struct adapts;
*
* The adaptor types libsigc++ provides
* are created with bind(), bind_return(), hide(), hide_return(),
- * retype_return(), retype(), compose(), exception_catch() and group().
+ * retype_return(), retype(), compose(), exception_catch(), track_obj()
+ * and group().
*
* You can easily derive your own adaptor type from sigc::adapts.
*/
/** Converts an arbitrary functor into an adaptor type.
- * All adaptor tyes in libsigc++ are unnumbered and have
+ * All adaptor types in libsigc++ have
* a <tt>template operator()</tt> member of every argument count
* they support. These functions in turn invoke a stored adaptor's
* <tt>template operator()</tt>, processing the arguments and return
diff --git a/sigc++/adaptors/macros/track_obj.h.m4 b/sigc++/adaptors/macros/track_obj.h.m4
new file mode 100644
index 0000000..d79c6d6
--- /dev/null
+++ b/sigc++/adaptors/macros/track_obj.h.m4
@@ -0,0 +1,218 @@
+dnl Copyright 2013, The libsigc++ Development Team
+dnl
+dnl This file is part of libsigc++.
+dnl
+dnl This library is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU Lesser General Public
+dnl License as published by the Free Software Foundation; either
+dnl version 2.1 of the License, or (at your option) any later version.
+dnl
+dnl This library is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl Lesser General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU Lesser General Public
+dnl License along with this library. If not, see <http://www.gnu.org/licenses/>.
+dnl
+divert(-1)
+
+include(template.macros.m4)
+
+define([TRACK_OBJECT_OPERATOR],[dnl
+ /** Invokes the wrapped functor passing on the arguments.dnl
+FOR(1, $1,[
+ * @param _A_arg%1 Argument to be passed on to the functor.])
+ * @return The return value of the functor invocation.
+ */
+ template <LOOP([typename T_arg%1], $1)>
+ typename deduce_result_type<LOOP(T_arg%1, $1)>::type
+ operator()(LOOP(T_arg%1 _A_arg%1, $1))
+ {
+ return this->functor_.SIGC_WORKAROUND_OPERATOR_PARENTHESES<LOOP([
+ _P_(T_arg%1)], $1)>
+ (LOOP(_A_arg%1, $1));
+ }
+
+ #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD
+ template <LOOP([typename T_arg%1], $1)>
+ typename deduce_result_type<LOOP(T_arg%1, $1)>::type
+ sun_forte_workaround(LOOP(T_arg%1 _A_arg%1, $1))
+ {
+ return this->functor_.SIGC_WORKAROUND_OPERATOR_PARENTHESES<LOOP([
+ _P_(T_arg%1)], $1)>
+ (LOOP(_A_arg%1, $1));
+ }
+ #endif
+
+])dnl end TRACK_OBJECT_OPERATOR
+
+dnl track_obj_functor[2..CALL_SIZE]. $1 is assumed to be >= 2.
+define([TRACK_OBJECT_FUNCTOR],[dnl
+/** track_obj_functor$1 wraps a functor and stores $1 references to trackable objects.
+ * Use the convenience function track_obj() to create an instance of track_obj_functor$1.
+ *
+ * @tparam T_functor The type of functor to wrap.dnl
+FOR(1,$1,[
+ * @tparam T_obj%1 The type of a trackable object.])
+ *
+ * @newin{2,4}
+ *
+ * @ingroup track_obj
+ */
+template <typename T_functor, LOOP(typename T_obj%1, $1)>
+class track_obj_functor$1 : public track_obj_functor1<T_functor, T_obj1>
+{
+public:
+ /** Constructs a track_obj_functor$1 object that wraps the passed functor and
+ * stores references to the passed trackable objects.
+ * @param _A_func Functor.dnl
+FOR(1,$1,[
+ * @param _A_obj%1 Trackable object.])
+ */
+ track_obj_functor$1(const T_functor& _A_func, LOOP(const T_obj%1& _A_obj%1, $1))
+ : track_obj_functor1<T_functor, T_obj1>(_A_func, _A_obj1)FOR(2,$1,[[, ]obj%1_(_A_obj%1)]) {}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+//protected:
+ // public, so that visit_each() can access it.dnl
+FOR(2,$1,[
+ const_limit_reference<T_obj%1> obj%1_;])
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+}; // end class track_obj_functor$1
+
+])dnl end TRACK_OBJECT_FUNCTOR
+
+define([TRACK_OBJECT_VISIT_EACH],[dnl
+//template specialization of visit_each<>(action, functor):
+/** Performs a functor on each of the targets of a functor.
+ * The function overload for sigc::track_obj_functor$1 performs a functor
+ * on the functor and on the trackable object instances stored in the
+ * sigc::track_obj_functor$1 object.
+ *
+ * @newin{2,4}
+ *
+ * @ingroup track_obj
+ */
+template <typename T_action, typename T_functor, LOOP(typename T_obj%1, $1)>
+void visit_each(const T_action& _A_action,
+ const track_obj_functor$1<T_functor, LOOP(T_obj%1, $1)>& _A_target)
+{
+ sigc::visit_each(_A_action, _A_target.functor_);dnl
+FOR(1,$1,[
+ sigc::visit_each(_A_action, _A_target.obj%1_);])
+}
+
+])dnl end TRACK_OBJECT_VISIT_EACH
+
+define([TRACK_OBJECT],[dnl
+/** Creates an adaptor of type sigc::track_obj_functor$1 which wraps a functor.
+ * @param _A_func Functor that shall be wrapped.dnl
+FOR(1,$1,[
+ * @param _A_obj%1 Trackable object.])
+ * @return Adaptor that executes _A_func() on invocation.
+ *
+ * @newin{2,4}
+ *
+ * @ingroup track_obj
+ */
+template <typename T_functor, LOOP(typename T_obj%1, $1)>
+inline track_obj_functor$1<T_functor, LOOP(T_obj%1, $1)>
+track_obj(const T_functor& _A_func, LOOP(const T_obj%1& _A_obj%1, $1))
+{
+ return track_obj_functor$1<T_functor, LOOP(T_obj%1, $1)>
+ (_A_func, LOOP(_A_obj%1, $1));
+}
+
+])dnl end TRACK_OBJECT
+
+divert(0)dnl
+__FIREWALL__
+#include <sigc++/adaptors/adaptor_trait.h>
+#include <sigc++/limit_reference.h>
+
+namespace sigc {
+
+/** @defgroup track_obj track_obj()
+ * track_obj() tracks trackable objects, referenced from a functor.
+ * It can be useful when you assign a C++11 lambda expression to a slot, or connect
+ * it to a signal, and the lambda expression contains references to sigc::trackable
+ * derived objects.
+ *
+ * The functor returned by sigc::track_obj() is formally an adaptor, but it does
+ * not alter the signature, return type or behaviour of the supplied functor.
+ * Up to CALL_SIZE objects can be tracked. operator()() can have up to CALL_SIZE arguments.
+ *
+ * @par Example:
+ * @code
+ * namespace sigc { SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE }
+ * struct bar : public sigc::trackable {};
+ * sigc::signal<void> some_signal;
+ * void foo(bar&);
+ * {
+ * bar some_bar;
+ * some_signal.connect([[&some_bar]](){ foo(some_bar); });
+ * // NOT disconnected automatically when some_bar goes out of scope
+ * some_signal.connect(sigc::track_obj([[&some_bar]](){ foo(some_bar); }, some_bar);
+ * // disconnected automatically when some_bar goes out of scope
+ * }
+ * @endcode
+ *
+ * @newin{2,4}
+ *
+ * @ingroup adaptors
+ */
+
+/** track_obj_functor1 wraps a functor and stores a reference to a trackable object.
+ * Use the convenience function track_obj() to create an instance of track_obj_functor1.
+ *
+ * @tparam T_functor The type of functor to wrap.
+ * @tparam T_obj1 The type of a trackable object.
+ *
+ * @newin{2,4}
+ *
+ * @ingroup track_obj
+ */
+template <typename T_functor, typename T_obj1>
+class track_obj_functor1 : public adapts<T_functor>
+{
+public:
+ typedef typename adapts<T_functor>::adaptor_type adaptor_type;
+
+ template <LOOP(typename T_arg%1=void, CALL_SIZE)>
+ struct deduce_result_type
+ { typedef typename adaptor_type::template deduce_result_type<LOOP(_P_(T_arg%1), CALL_SIZE)>::type type; };
+ typedef typename adaptor_type::result_type result_type;
+
+ /** Constructs a track_obj_functor1 object that wraps the passed functor and
+ * stores a reference to the passed trackable object.
+ * @param _A_func Functor.
+ * @param _A_obj1 Trackable object.
+ */
+ track_obj_functor1(const T_functor& _A_func, const T_obj1& _A_obj1)
+ : adapts<T_functor>(_A_func), obj1_(_A_obj1) {}
+
+ /** Invokes the wrapped functor.
+ * @return The return value of the functor invocation.
+ */
+ result_type operator()()
+ { return this->functor_(); }
+
+FOR(1,CALL_SIZE,[[TRACK_OBJECT_OPERATOR(%1)]])dnl
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+//protected:
+ // public, so that visit_each() can access it.
+ const_limit_reference<T_obj1> obj1_;
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+}; // end class track_obj_functor1
+
+FOR(2,CALL_SIZE,[[TRACK_OBJECT_FUNCTOR(%1)]])dnl
+
+FOR(1,CALL_SIZE,[[TRACK_OBJECT_VISIT_EACH(%1)]])dnl
+
+FOR(1,CALL_SIZE,[[TRACK_OBJECT(%1)]])dnl
+
+} /* namespace sigc */
diff --git a/sigc++/filelist.am b/sigc++/filelist.am
index dc90d3f..b230902 100644
--- a/sigc++/filelist.am
+++ b/sigc++/filelist.am
@@ -30,10 +30,12 @@ functors_built_h = functor_trait.h slot.h ptr_fun.h mem_fun.h
# Adaptors (adaptors/)
adaptors_m4 = deduce_result_type.h.m4 adaptor_trait.h.m4 bind.h.m4 bind_return.h.m4 \
- retype_return.h.m4 hide.h.m4 retype.h.m4 compose.h.m4 exception_catch.h.m4
+ retype_return.h.m4 hide.h.m4 retype.h.m4 compose.h.m4 exception_catch.h.m4 \
+ track_obj.h.m4
adaptors_built_cc =
adaptors_built_h = deduce_result_type.h adaptor_trait.h bind.h bind_return.h \
- retype_return.h hide.h retype.h compose.h exception_catch.h
+ retype_return.h hide.h retype.h compose.h exception_catch.h \
+ track_obj.h
# Lambda (adaptors/lambda)
lambda_m4 = base.h.m4 select.h.m4 operator.h.m4 group.h.m4 lambda.cc.m4
diff --git a/tests/.gitignore b/tests/.gitignore
index 630aeb3..dfc65dd 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -25,3 +25,4 @@
/test_slot
/test_slot_disconnect
/test_trackable
+/test_track_obj
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 067fd71..367cdd4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -46,7 +46,8 @@ check_PROGRAMS = \
test_size \
test_slot \
test_slot_disconnect \
- test_trackable
+ test_trackable \
+ test_track_obj
TESTS = $(check_PROGRAMS)
@@ -79,6 +80,7 @@ test_size_SOURCES = test_size.cc $(sigc_test_util)
test_slot_SOURCES = test_slot.cc $(sigc_test_util)
test_slot_disconnect_SOURCES = test_slot_disconnect.cc $(sigc_test_util)
test_trackable_SOURCES = test_trackable.cc $(sigc_test_util)
+test_track_obj_SOURCES = test_track_obj.cc $(sigc_test_util)
# 2005-01-19
# Disabled: test_lambda - The Tru64 compiler can't build this when not using
diff --git a/tests/test_cpp11_lambda.cc b/tests/test_cpp11_lambda.cc
index ad0271d..463c69e 100644
--- a/tests/test_cpp11_lambda.cc
+++ b/tests/test_cpp11_lambda.cc
@@ -32,7 +32,8 @@
// The only real disadvantage of the C++11 lambda expressions is that a slot that
// contains an object derived from sigc::trackable is not automatically disconnected
// when the object is deleted, if a reference to the object is stored in a C++11
-// lambda expression, connected to the slot.
+// lambda expression, connected to the slot. But if you use sigc::track_obj(),
+// the slot is automatically disconnected. Thus, the disadvantage is insignificant.
//
// To test the C++11 lambda expressions with gcc 4.6.3 (and probably some later
// versions of gcc; gcc 4.7.x also understands -std=c++11):
@@ -54,6 +55,7 @@
#include <sigc++/functors/functors.h>
#include <sigc++/bind.h>
#include <sigc++/reference_wrapper.h>
+#include <sigc++/adaptors/track_obj.h>
#include <sigc++/signal.h>
#ifdef USING_CPP11_LAMBDA_EXPRESSIONS
@@ -270,20 +272,15 @@ int main(int argc, char* argv[])
// auto-disconnect
// Here's an area where the libsigc++ lambda expressions are advantageous.
- // It can be more difficult to auto-disconnect slots without them.
+ // If you want to auto-disconnect a slot with a C++11 lambda expression
+ // that contains references to sigc::trackable-derived objects, you must use
+ // sigc::track_obj().
sigc::slot<void, std::ostringstream&> sl1;
{
- struct printable_book : public book
- {
- explicit printable_book(const std::string& name) : book(name) {}
- void operator()(std::ostringstream& stream) { stream << *this << "\n"; }
- };
- //book guest_book("karl");
- printable_book printable_guest_book("karl");
- // sl1 = (sigc::var(std::cout) << sigc::ref(guest_book) << sigc::var("\n"));
- // sl1 = [&guest_book](){ result_stream << guest_book << "\n"; }; // no auto-disconnect
- // sl1 = printable_guest_book; // no auto-disconnect, no error; a copy is stored in sl1
- sl1 = sigc::mem_fun(printable_guest_book, &printable_book::operator());
+ book guest_book("karl");
+ //sl1 = (sigc::var(std::cout) << sigc::ref(guest_book) << sigc::var("\n"));
+ // sl1 = [&guest_book](std::ostringstream& stream){ stream << guest_book << "\n"; }; // no auto-disconnect
+ sl1 = sigc::track_obj([&guest_book](std::ostringstream& stream){ stream << guest_book << "\n"; }, guest_book);
sl1(result_stream);
util->check_result(result_stream, "karl\n");
@@ -327,7 +324,7 @@ int main(int argc, char* argv[])
//sl2 = sigc::group(&egon, sigc::ref(guest_book));
// sl2 = [&guest_book] () { egon(guest_book); }; // no auto-disconnect
// sl2 = std::bind(&egon, std::ref(guest_book)); // does not compile (gcc 4.6.3)
- sl2 = sigc::bind(&egon, sigc::ref(guest_book));
+ sl2 = sigc::track_obj([&guest_book] () { egon(guest_book); }, guest_book);
sl2();
util->check_result(result_stream, "egon(string 'karl')");
@@ -463,14 +460,15 @@ int main(int argc, char* argv[])
}
{
- struct bar : public sigc::trackable {} some_bar;
+ //struct bar : public sigc::trackable {} some_bar;
sigc::signal<void> some_signal;
{
bar_group4 some_bar;
//some_signal.connect(sigc::group(&foo,sigc::ref(some_bar)));
// disconnected automatically if some_bar goes out of scope
//some_signal.connect([&some_bar](){ foo_group4(some_bar); }); // no auto-disconnect
- some_signal.connect(sigc::bind(&foo_group4, sigc::ref(some_bar)));
+ //some_signal.connect(sigc::bind(&foo_group4, sigc::ref(some_bar))); // auto-disconnects, but we prefer C++11 lambda
+ some_signal.connect(sigc::track_obj([&some_bar](){ foo_group4(some_bar); }, some_bar));
some_signal.emit();
util->check_result(result_stream, "foo_group4(bar_group4&)");
}
diff --git a/tests/test_track_obj.cc b/tests/test_track_obj.cc
new file mode 100644
index 0000000..5e8a824
--- /dev/null
+++ b/tests/test_track_obj.cc
@@ -0,0 +1,230 @@
+/* Copyright (C) 2013 The libsigc++ Development Team
+ *
+ * This file is part of libsigc++.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// The purpose of this test case is threefold.
+// - Test sigc::track_obj().
+// - Show that a slot with a C++11 lambda expression can be automatically
+// disconnected when an object derived from sigc::trackable is deleted,
+// provided sigc::track_obj() is used.
+// It's shown here as a preparation for deprecating and eventually
+// deleting the libsigc++ lambda expressions.
+// See https://bugzilla.gnome.org/show_bug.cgi?id=672555
+// - Test the code example in the documentation in sigc++/adaptors/track_obj.h.
+//
+// To test the C++11 lambda expressions with gcc 4.6.3 (and probably some later
+// versions of gcc; gcc 4.7.x also understands -std=c++11):
+// make CXXFLAGS='-g -O2 -std=c++0x' test_track_obj
+// ./test_track_obj
+// echo $?
+// If test_track_obj writes nothing and the return code is 0, the test has passed.
+
+#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define USING_CPP11_LAMBDA_EXPRESSIONS
+#endif
+
+#include "testutilities.h"
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <cstdlib>
+#include <sigc++/adaptors/track_obj.h>
+#include <sigc++/signal.h>
+
+#ifdef USING_CPP11_LAMBDA_EXPRESSIONS
+namespace sigc
+{
+ SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
+}
+#endif
+
+namespace
+{
+std::ostringstream result_stream;
+
+void egon(std::string& str)
+{
+ result_stream << "egon(string '" << str << "')";
+ str = "egon was here";
+}
+
+struct book : public sigc::trackable
+{
+ explicit book(const std::string& name) : name_(name) {}
+ operator std::string& () { return name_; }
+ operator const std::string& () const { return name_; }
+ std::string name_;
+};
+
+inline std::ostringstream& operator << (std::ostringstream& s, const book& b)
+{
+ s << b.name_;
+ return s;
+}
+
+struct bar_group4 : public sigc::trackable
+{
+};
+
+class Functor1 : public sigc::functor_base
+{
+public:
+ typedef std::string result_type;
+
+ Functor1(const bar_group4& bar)
+ : bar_(bar) {}
+
+ std::string operator()(int i)
+ {
+ return (i<0) ? "negative" : ((i>0) ? "positive" : "zero");
+ }
+
+private:
+ const bar_group4& bar_;
+};
+
+class Functor2 : public sigc::functor_base
+{
+public:
+ typedef std::string result_type;
+
+ Functor2(const bar_group4& bar, const book& aBook)
+ : bar_(bar), aBook_(aBook) {}
+
+ std::string operator()(int i, const std::string& str) const
+ {
+ std::string result = (i<0) ? "negative, " : ((i>0) ? "positive, " : "zero, ");
+ result += str;
+ result += aBook_;
+ return result;
+ }
+
+private:
+ const bar_group4& bar_;
+ const book& aBook_;
+};
+
+void foo_group4(bar_group4&)
+{
+ result_stream << "foo_group4(bar_group4&)";
+}
+
+} // end anonymous namespace
+
+
+int main(int argc, char* argv[])
+{
+ TestUtilities* util = TestUtilities::get_instance();
+
+ if (!util->check_command_args(argc, argv))
+ return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
+
+ sigc::slot<std::string, int> sl1;
+ {
+ bar_group4 bar4;
+ sl1 = sigc::track_obj(Functor1(bar4), bar4);
+ result_stream << sl1(-2);
+ util->check_result(result_stream, "negative");
+
+ } // auto-disconnect sl1
+
+ result_stream << sl1(-2);
+ util->check_result(result_stream, "");
+
+ // Allocate on the heap. valgrind can then find erroneous memory accesses.
+ // (There should be none, of course.)
+ sigc::slot<std::string, int, std::string>* psl2 = new sigc::slot<std::string, int, std::string>;
+ bar_group4* pbar4 = new bar_group4;
+ book* pbook4 = new book("A Book");
+ *psl2 = sigc::track_obj(Functor2(*pbar4, *pbook4), *pbar4, *pbook4);
+ result_stream << (*psl2)(0, "Book title: ");
+ util->check_result(result_stream, "zero, Book title: A Book");
+
+ delete pbook4; // auto-disconnect *psl2
+ pbook4 = 0;
+ result_stream << (*psl2)(0, "Book title: ");
+ util->check_result(result_stream, "");
+ delete psl2;
+ psl2 = 0;
+ delete pbar4;
+ pbar4 = 0;
+
+#ifdef USING_CPP11_LAMBDA_EXPRESSIONS
+
+ // auto-disconnect
+ // If you want to auto-disconnect a slot with a C++11 lambda expression
+ // that contains references to sigc::trackable-derived objects, you must use
+ // sigc::track_obj().
+ sigc::slot<void, std::ostringstream&> sl10;
+ {
+ book guest_book("karl");
+ // sl1 = [&guest_book](std::ostringstream& stream){ stream << guest_book << "\n"; }; // no auto-disconnect
+ sl10 = sigc::track_obj([&guest_book](std::ostringstream& stream){ stream << guest_book; }, guest_book);
+ sl10(result_stream);
+ util->check_result(result_stream, "karl");
+
+ } // auto-disconnect sl10
+
+ sl10(result_stream);
+ util->check_result(result_stream, "");
+
+ // auto-disconnect
+ sigc::slot<void> sl20;
+ {
+ book guest_book("karl");
+ // sl2 = [&guest_book] () { egon(guest_book); }; // no auto-disconnect
+ // sl2 = std::bind(&egon, std::ref(guest_book)); // does not compile (gcc 4.6.3)
+ sl20 = sigc::track_obj([&guest_book] () { egon(guest_book); }, guest_book);
+ sl20();
+ util->check_result(result_stream, "egon(string 'karl')");
+
+ result_stream << static_cast<const std::string&>(guest_book);
+ util->check_result(result_stream, "egon was here");
+
+ } // auto-disconnect sl20
+
+ sl20();
+ util->check_result(result_stream, "");
+
+
+ // Code example in the documentation sigc++/adaptors/macros/track_obj.h.m4
+ // -----------------------------------------------------------------------
+ {
+ //struct bar : public sigc::trackable {} some_bar;
+ sigc::signal<void> some_signal;
+ {
+ bar_group4 some_bar;
+ //some_signal.connect(sigc::group(&foo,sigc::ref(some_bar)));
+ // disconnected automatically if some_bar goes out of scope
+ //some_signal.connect([&some_bar](){ foo_group4(some_bar); }); // no auto-disconnect
+ //some_signal.connect(sigc::bind(&foo_group4, sigc::ref(some_bar))); // auto-disconnects, but we prefer C++11 lambda
+ some_signal.connect(sigc::track_obj([&some_bar](){ foo_group4(some_bar); }, some_bar));
+ some_signal.emit();
+ util->check_result(result_stream, "foo_group4(bar_group4&)");
+
+ } // auto-disconnect the lambda expression
+
+ some_signal.emit();
+ util->check_result(result_stream, "");
+ }
+
+#else // not USING_CPP11_LAMBDA_EXPRESSIONS
+ std::cout << "The compiler capabilities don't allow test of C++11 lambda expressions." << std::endl;
+#endif
+
+ return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
+}