summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjell Ahlstedt <kjellahlstedt@gmail.com>2022-04-20 14:54:30 +0200
committerKjell Ahlstedt <kjellahlstedt@gmail.com>2022-04-20 15:01:37 +0200
commit6fb6f9dfc2858e3681aadbd178d13b38da043246 (patch)
treee1a846c7275c4eff6c3d809796bb261502c10cb6
parentbaab13fd40d90dc0a33241a4bd517f985479a0c5 (diff)
downloadsigc++-6fb6f9dfc2858e3681aadbd178d13b38da043246.tar.gz
Add track_object(), deprecate track_obj()
track_object() checks that the listed objects derive from sigc::trackable. Fixes #78
-rw-r--r--sigc++/adaptors/track_obj.h45
-rw-r--r--tests/test_track_obj.cc80
2 files changed, 85 insertions, 40 deletions
diff --git a/sigc++/adaptors/track_obj.h b/sigc++/adaptors/track_obj.h
index 6f208f3..7f895b2 100644
--- a/sigc++/adaptors/track_obj.h
+++ b/sigc++/adaptors/track_obj.h
@@ -23,19 +23,24 @@
#include <sigc++/adaptors/tuple_visitor_visit_each.h>
#include <sigc++/limit_reference.h>
#include <sigc++/tuple-utils/tuple_for_each.h>
+#include <sigc++/trackable.h>
+#include <type_traits>
+#include <algorithm>
namespace sigc
{
-/** @defgroup track_obj track_obj()
- * sigc::track_obj() tracks trackable objects, referenced from a functor.
+/** @defgroup track_obj track_obj(), track_object()
+ * sigc::track_object() tracks trackable objects, referenced from a functor.
* It can be useful when you assign a C++11 lambda expression or a std::function<>
* to a slot, or connect it to a signal, and the lambda expression or std::function<>
* contains references to sigc::trackable derived objects.
*
- * The functor returned by sigc::track_obj() is formally an adaptor, but it does
+ * The functor returned by sigc::track_object() is formally an adaptor, but it does
* not alter the signature, return type or behaviour of the supplied functor.
*
+ * track_obj() is a deprecated alternative to track_object().
+ *
* @par Example:
* @code
* struct bar : public sigc::trackable {};
@@ -45,18 +50,18 @@ namespace sigc
* 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);
+ * some_signal.connect(sigc::track_object([&some_bar](){ foo(some_bar); }, some_bar);
* // disconnected automatically when some_bar goes out of scope
* }
* @endcode
*
- * @newin{2,4}
- *
* @ingroup adaptors
*/
-/** track_obj_functor wraps a functor and stores a reference to a trackable object.
- * Use the convenience function track_obj() to create an instance of track_obj_functor.
+/** %track_obj_functor wraps a functor and stores a reference to a trackable object.
+ * Use the convenience function track_object() to create an instance of %track_obj_functor.
+ *
+ * track_obj() is a deprecated alternative to track_object().
*
* @tparam T_functor The type of functor to wrap.
* @tparam T_obj The types of the trackable objects.
@@ -124,12 +129,14 @@ struct visitor<track_obj_functor<T_functor, T_obj...>>
};
#endif // DOXYGEN_SHOULD_SKIP_THIS
+#ifndef SIGCXX_DISABLE_DEPRECATED
/** Creates an adaptor of type sigc::track_obj_functor which wraps a functor.
* @param func Functor that shall be wrapped.
* @param obj Trackable objects.
* @return Adaptor that executes func() on invocation.
*
* @newin{2,4}
+ * @deprecated Use sigc::track_object() instead.
*
* @ingroup track_obj
*/
@@ -139,6 +146,28 @@ track_obj(const T_functor& func, const T_obj&... obj)
{
return track_obj_functor<T_functor, T_obj...>(func, obj...);
}
+#endif // SIGCXX_DISABLE_DEPRECATED
+
+/** Creates an adaptor of type sigc::track_obj_functor which wraps a functor.
+ * @param func Functor that shall be wrapped.
+ * @param obj1 Trackable object, derived directly or indirectly from sigc::trackable.
+ * @param objs Zero or more trackable objects, derived directly or indirectly from sigc::trackable.
+ * @return Adaptor that executes func() on invocation.
+ *
+ * @newin{3,4}
+ *
+ * @ingroup track_obj
+ */
+template<typename T_functor, typename T_obj1, typename... T_objs>
+inline decltype(auto)
+track_object(const T_functor& func, const T_obj1& obj1, const T_objs&... objs)
+{
+ static_assert(std::min<bool>({std::is_base_of<sigc::trackable, T_obj1>::value,
+ std::is_base_of<sigc::trackable, T_objs>::value...}),
+ "Each trackable object must be derived from sigc::trackable.");
+
+ return track_obj_functor<T_functor, T_obj1, T_objs...>(func, obj1, objs...);
+}
} /* namespace sigc */
diff --git a/tests/test_track_obj.cc b/tests/test_track_obj.cc
index aefdb07..54b4430 100644
--- a/tests/test_track_obj.cc
+++ b/tests/test_track_obj.cc
@@ -17,10 +17,10 @@
*/
// The purpose of this test case is threefold.
-// - Test sigc::track_obj().
+// - Test sigc::track_obj() and sigc::track_object().
// - 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.
+// provided sigc::track_obj() or sigc::track_object() is used.
// It shows that C++11 lambda expressions can replace the libsigc++ lambda
// expressions, which have been removed.
// See https://bugzilla.gnome.org/show_bug.cgi?id=672555
@@ -115,32 +115,38 @@ main(int argc, char* argv[])
return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
sigc::slot<std::string(int)> sl1;
+ sigc::slot<std::string(int)> sl2;
{
bar_group4 bar4;
sl1 = sigc::track_obj(Functor1(bar4), bar4);
- result_stream << sl1(-2);
- util->check_result(result_stream, "negative");
+ sl2 = sigc::track_object(Functor1(bar4), bar4);
+ result_stream << sl1(-2) << ", " << sl2(2);
+ util->check_result(result_stream, "negative, positive");
- } // auto-disconnect sl1
+ } // auto-disconnect sl1 and sl2
- result_stream << sl1(-2);
- util->check_result(result_stream, "");
+ result_stream << sl1(-2) << ", " << sl2(2);
+ util->check_result(result_stream, ", ");
// Allocate on the heap. valgrind can then find erroneous memory accesses.
// (There should be none, of course.)
- auto psl2 = new sigc::slot<std::string(int, std::string)>;
+ auto psl3 = new sigc::slot<std::string(int, std::string)>;
+ auto psl4 = new sigc::slot<std::string(int, std::string)>;
auto pbar4 = new bar_group4;
auto 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");
+ *psl3 = sigc::track_obj(Functor2(*pbar4, *pbook4), *pbar4, *pbook4);
+ *psl4 = sigc::track_object(Functor2(*pbar4, *pbook4), *pbar4, *pbook4);
+ result_stream << (*psl3)(0, "Book title: ") << ", " << (*psl4)(1, "Title: ");
+ util->check_result(result_stream, "zero, Book title: A Book, positive, Title: A Book");
- delete pbook4; // auto-disconnect *psl2
+ delete pbook4; // auto-disconnect *psl3 and *psl4
pbook4 = nullptr;
- result_stream << (*psl2)(0, "Book title: ");
- util->check_result(result_stream, "");
- delete psl2;
- psl2 = nullptr;
+ result_stream << (*psl3)(0, "Book title: ") << ", " << (*psl4)(1, "Title: ");
+ util->check_result(result_stream, ", ");
+ delete psl3;
+ psl3 = nullptr;
+ delete psl4;
+ psl4 = nullptr;
delete pbar4;
pbar4 = nullptr;
@@ -149,38 +155,47 @@ main(int argc, char* argv[])
// 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;
+ // sigc::track_obj() or sigc::track_object().
+ sigc::slot<void(std::ostringstream&)> sl11;
+ sigc::slot<void(std::ostringstream&)> sl12;
{
book guest_book("karl");
- // sl1 = [&guest_book](std::ostringstream& stream){ stream << guest_book << "\n"; }; // no
- // auto-disconnect
- sl10 = sigc::track_obj(
+ // no auto-disconnect
+ // sl1 = [&guest_book](std::ostringstream& stream){ stream << guest_book << "\n"; };
+ sl11 = sigc::track_obj(
+ [&guest_book](std::ostringstream& stream) { stream << guest_book; }, guest_book);
+ sl12 = sigc::track_object(
[&guest_book](std::ostringstream& stream) { stream << guest_book; }, guest_book);
- sl10(result_stream);
- util->check_result(result_stream, "karl");
+ sl11(result_stream);
+ sl12(result_stream);
+ util->check_result(result_stream, "karlkarl");
- } // auto-disconnect sl10
+ } // auto-disconnect sl11 and sl12
- sl10(result_stream);
+ sl11(result_stream);
+ sl12(result_stream);
util->check_result(result_stream, "");
// auto-disconnect
- sigc::slot<void()> sl20;
+ sigc::slot<void()> sl21;
+ sigc::slot<void()> sl22;
{
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')");
+ sl21 = sigc::track_obj([&guest_book]() { egon(guest_book); }, guest_book);
+ sl22 = sigc::track_obj([&guest_book]() { egon(guest_book); }, guest_book);
+ sl21();
+ sl22();
+ util->check_result(result_stream, "egon(string 'karl')egon(string 'egon was here')");
result_stream << static_cast<const std::string&>(guest_book);
util->check_result(result_stream, "egon was here");
- } // auto-disconnect sl20
+ } // auto-disconnect sl21 and sl22
- sl20();
+ sl21();
+ sl22();
util->check_result(result_stream, "");
// Code example in the documentation sigc++/adaptors/track_obj.h.
@@ -194,8 +209,9 @@ main(int argc, char* argv[])
// some_signal.connect(sigc::bind(&foo_group4, std::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.connect(sigc::track_object([&some_bar]() { foo_group4(some_bar); }, some_bar));
some_signal.emit();
- util->check_result(result_stream, "foo_group4(bar_group4&)");
+ util->check_result(result_stream, "foo_group4(bar_group4&)foo_group4(bar_group4&)");
} // auto-disconnect the lambda expression