diff options
author | Kjell Ahlstedt <kjellahlstedt@gmail.com> | 2022-04-20 14:41:52 +0200 |
---|---|---|
committer | Kjell Ahlstedt <kjellahlstedt@gmail.com> | 2022-04-20 14:47:50 +0200 |
commit | e51bf59955d7a6f32b6f653e4f8fca4e821d61f9 (patch) | |
tree | 5a1b7b20ab08203714dded12f112246d0b90b88b | |
parent | 4bb3060056adeba0bf3be0ddf5e5c9f0d9d5b29a (diff) | |
download | sigc++-e51bf59955d7a6f32b6f653e4f8fca4e821d61f9.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/macros/track_obj.h.m4 | 45 | ||||
-rw-r--r-- | tests/test_track_obj.cc | 92 |
2 files changed, 87 insertions, 50 deletions
diff --git a/sigc++/adaptors/macros/track_obj.h.m4 b/sigc++/adaptors/macros/track_obj.h.m4 index 9f7d8c2..dbce2be 100644 --- a/sigc++/adaptors/macros/track_obj.h.m4 +++ b/sigc++/adaptors/macros/track_obj.h.m4 @@ -50,7 +50,7 @@ FOR(1, $1,[ 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. + * Use the convenience function track_object() to create an instance of track_obj_functor$1. * * @tparam T_functor The type of functor to wrap.dnl FOR(1,$1,[ @@ -111,6 +111,7 @@ FOR(1,$1,[ ])dnl end TRACK_OBJECT_VISIT_EACH define([TRACK_OBJECT],[dnl +_DEPRECATE_IFDEF_START /** 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,[ @@ -118,6 +119,7 @@ FOR(1,$1,[ * @return Adaptor that executes _A_func() on invocation. * * @newin{2,4} + * @deprecated Use sigc::track_object() instead. * * @ingroup track_obj */ @@ -128,26 +130,54 @@ 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)); } +_DEPRECATE_IFDEF_END ])dnl end TRACK_OBJECT +define([TRACK_OBJECT2],[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, derived directly or indirectly from sigc::trackable.]]) + * @return Adaptor that executes _A_func() on invocation. + * + * @newin{2,12} + * + * @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_object(const T_functor& _A_func, LOOP(const T_obj%1& _A_obj%1, $1)) +{ + static_assert(LOOP([[std::is_base_of<sigc::trackable, T_obj%1>::value]], $1, [ && ]), + "Each trackable object must be derived from sigc::trackable."); + + return track_obj_functor$1<T_functor, LOOP(T_obj%1, $1)> + (_A_func, LOOP(_A_obj%1, $1)); +} + +])dnl end TRACK_OBJECT2 + divert(0)dnl _FIREWALL([ADAPTORS_TRACK_OBJ]) #include <sigc++/adaptors/adaptor_trait.h> #include <sigc++/limit_reference.h> +#include <type_traits> 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. * Up to CALL_SIZE objects can be tracked. operator()() can have up to CALL_SIZE arguments. * + * track_obj() is a deprecated alternative to track_object(). + * * @par Example: * @code * struct bar : public sigc::trackable {}; @@ -157,18 +187,16 @@ 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_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. + * Use the convenience function track_object() 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. @@ -221,5 +249,6 @@ FOR(1,CALL_SIZE,[[TRACK_OBJECT_VISIT_EACH(%1)]])dnl #endif // DOXYGEN_SHOULD_SKIP_THIS FOR(1,CALL_SIZE,[[TRACK_OBJECT(%1)]])dnl +FOR(1,CALL_SIZE,[[TRACK_OBJECT2(%1)]])dnl } /* namespace sigc */ diff --git a/tests/test_track_obj.cc b/tests/test_track_obj.cc index 6c1fa24..3a7cf41 100644 --- a/tests/test_track_obj.cc +++ b/tests/test_track_obj.cc @@ -17,23 +17,17 @@ */ // 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 // - 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. - #include "testutilities.h" #include <string> #include <iostream> @@ -130,74 +124,88 @@ int 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>; 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"); + *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; - -//C++11 lambda expressions: + // C++11 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; + // 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([&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); + 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); + sl11(result_stream); + sl12(result_stream); + util->check_result(result_stream, "karlkarl"); + + } // auto-disconnect sl11 and sl12 + + 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/macros/track_obj.h.m4 // ----------------------------------------------------------------------- { @@ -210,8 +218,9 @@ int main(int argc, char* argv[]) //some_signal.connect([&some_bar](){ foo_group4(some_bar); }); // no auto-disconnect //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 @@ -219,6 +228,5 @@ int main(int argc, char* argv[]) util->check_result(result_stream, ""); } - return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE; } |