Skip to content

Commit 6fb6f9d

Browse files
committed
Add track_object(), deprecate track_obj()
track_object() checks that the listed objects derive from sigc::trackable. Fixes #78
1 parent baab13f commit 6fb6f9d

File tree

2 files changed

+85
-40
lines changed

2 files changed

+85
-40
lines changed

sigc++/adaptors/track_obj.h

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,24 @@
2323
#include <sigc++/adaptors/tuple_visitor_visit_each.h>
2424
#include <sigc++/limit_reference.h>
2525
#include <sigc++/tuple-utils/tuple_for_each.h>
26+
#include <sigc++/trackable.h>
27+
#include <type_traits>
28+
#include <algorithm>
2629

2730
namespace sigc
2831
{
2932

30-
/** @defgroup track_obj track_obj()
31-
* sigc::track_obj() tracks trackable objects, referenced from a functor.
33+
/** @defgroup track_obj track_obj(), track_object()
34+
* sigc::track_object() tracks trackable objects, referenced from a functor.
3235
* It can be useful when you assign a C++11 lambda expression or a std::function<>
3336
* to a slot, or connect it to a signal, and the lambda expression or std::function<>
3437
* contains references to sigc::trackable derived objects.
3538
*
36-
* The functor returned by sigc::track_obj() is formally an adaptor, but it does
39+
* The functor returned by sigc::track_object() is formally an adaptor, but it does
3740
* not alter the signature, return type or behaviour of the supplied functor.
3841
*
42+
* track_obj() is a deprecated alternative to track_object().
43+
*
3944
* @par Example:
4045
* @code
4146
* struct bar : public sigc::trackable {};
@@ -45,18 +50,18 @@ namespace sigc
4550
* bar some_bar;
4651
* some_signal.connect([&some_bar](){ foo(some_bar); });
4752
* // NOT disconnected automatically when some_bar goes out of scope
48-
* some_signal.connect(sigc::track_obj([&some_bar](){ foo(some_bar); }, some_bar);
53+
* some_signal.connect(sigc::track_object([&some_bar](){ foo(some_bar); }, some_bar);
4954
* // disconnected automatically when some_bar goes out of scope
5055
* }
5156
* @endcode
5257
*
53-
* @newin{2,4}
54-
*
5558
* @ingroup adaptors
5659
*/
5760

58-
/** track_obj_functor wraps a functor and stores a reference to a trackable object.
59-
* Use the convenience function track_obj() to create an instance of track_obj_functor.
61+
/** %track_obj_functor wraps a functor and stores a reference to a trackable object.
62+
* Use the convenience function track_object() to create an instance of %track_obj_functor.
63+
*
64+
* track_obj() is a deprecated alternative to track_object().
6065
*
6166
* @tparam T_functor The type of functor to wrap.
6267
* @tparam T_obj The types of the trackable objects.
@@ -124,12 +129,14 @@ struct visitor<track_obj_functor<T_functor, T_obj...>>
124129
};
125130
#endif // DOXYGEN_SHOULD_SKIP_THIS
126131

132+
#ifndef SIGCXX_DISABLE_DEPRECATED
127133
/** Creates an adaptor of type sigc::track_obj_functor which wraps a functor.
128134
* @param func Functor that shall be wrapped.
129135
* @param obj Trackable objects.
130136
* @return Adaptor that executes func() on invocation.
131137
*
132138
* @newin{2,4}
139+
* @deprecated Use sigc::track_object() instead.
133140
*
134141
* @ingroup track_obj
135142
*/
@@ -139,6 +146,28 @@ track_obj(const T_functor& func, const T_obj&... obj)
139146
{
140147
return track_obj_functor<T_functor, T_obj...>(func, obj...);
141148
}
149+
#endif // SIGCXX_DISABLE_DEPRECATED
150+
151+
/** Creates an adaptor of type sigc::track_obj_functor which wraps a functor.
152+
* @param func Functor that shall be wrapped.
153+
* @param obj1 Trackable object, derived directly or indirectly from sigc::trackable.
154+
* @param objs Zero or more trackable objects, derived directly or indirectly from sigc::trackable.
155+
* @return Adaptor that executes func() on invocation.
156+
*
157+
* @newin{3,4}
158+
*
159+
* @ingroup track_obj
160+
*/
161+
template<typename T_functor, typename T_obj1, typename... T_objs>
162+
inline decltype(auto)
163+
track_object(const T_functor& func, const T_obj1& obj1, const T_objs&... objs)
164+
{
165+
static_assert(std::min<bool>({std::is_base_of<sigc::trackable, T_obj1>::value,
166+
std::is_base_of<sigc::trackable, T_objs>::value...}),
167+
"Each trackable object must be derived from sigc::trackable.");
168+
169+
return track_obj_functor<T_functor, T_obj1, T_objs...>(func, obj1, objs...);
170+
}
142171

143172
} /* namespace sigc */
144173

tests/test_track_obj.cc

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
*/
1818

1919
// The purpose of this test case is threefold.
20-
// - Test sigc::track_obj().
20+
// - Test sigc::track_obj() and sigc::track_object().
2121
// - Show that a slot with a C++11 lambda expression can be automatically
2222
// disconnected when an object derived from sigc::trackable is deleted,
23-
// provided sigc::track_obj() is used.
23+
// provided sigc::track_obj() or sigc::track_object() is used.
2424
// It shows that C++11 lambda expressions can replace the libsigc++ lambda
2525
// expressions, which have been removed.
2626
// See https://bugzilla.gnome.org/show_bug.cgi?id=672555
@@ -115,32 +115,38 @@ main(int argc, char* argv[])
115115
return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
116116

117117
sigc::slot<std::string(int)> sl1;
118+
sigc::slot<std::string(int)> sl2;
118119
{
119120
bar_group4 bar4;
120121
sl1 = sigc::track_obj(Functor1(bar4), bar4);
121-
result_stream << sl1(-2);
122-
util->check_result(result_stream, "negative");
122+
sl2 = sigc::track_object(Functor1(bar4), bar4);
123+
result_stream << sl1(-2) << ", " << sl2(2);
124+
util->check_result(result_stream, "negative, positive");
123125

124-
} // auto-disconnect sl1
126+
} // auto-disconnect sl1 and sl2
125127

126-
result_stream << sl1(-2);
127-
util->check_result(result_stream, "");
128+
result_stream << sl1(-2) << ", " << sl2(2);
129+
util->check_result(result_stream, ", ");
128130

129131
// Allocate on the heap. valgrind can then find erroneous memory accesses.
130132
// (There should be none, of course.)
131-
auto psl2 = new sigc::slot<std::string(int, std::string)>;
133+
auto psl3 = new sigc::slot<std::string(int, std::string)>;
134+
auto psl4 = new sigc::slot<std::string(int, std::string)>;
132135
auto pbar4 = new bar_group4;
133136
auto pbook4 = new book("A Book");
134-
*psl2 = sigc::track_obj(Functor2(*pbar4, *pbook4), *pbar4, *pbook4);
135-
result_stream << (*psl2)(0, "Book title: ");
136-
util->check_result(result_stream, "zero, Book title: A Book");
137+
*psl3 = sigc::track_obj(Functor2(*pbar4, *pbook4), *pbar4, *pbook4);
138+
*psl4 = sigc::track_object(Functor2(*pbar4, *pbook4), *pbar4, *pbook4);
139+
result_stream << (*psl3)(0, "Book title: ") << ", " << (*psl4)(1, "Title: ");
140+
util->check_result(result_stream, "zero, Book title: A Book, positive, Title: A Book");
137141

138-
delete pbook4; // auto-disconnect *psl2
142+
delete pbook4; // auto-disconnect *psl3 and *psl4
139143
pbook4 = nullptr;
140-
result_stream << (*psl2)(0, "Book title: ");
141-
util->check_result(result_stream, "");
142-
delete psl2;
143-
psl2 = nullptr;
144+
result_stream << (*psl3)(0, "Book title: ") << ", " << (*psl4)(1, "Title: ");
145+
util->check_result(result_stream, ", ");
146+
delete psl3;
147+
psl3 = nullptr;
148+
delete psl4;
149+
psl4 = nullptr;
144150
delete pbar4;
145151
pbar4 = nullptr;
146152

@@ -149,38 +155,47 @@ main(int argc, char* argv[])
149155
// auto-disconnect
150156
// If you want to auto-disconnect a slot with a C++11 lambda expression
151157
// that contains references to sigc::trackable-derived objects, you must use
152-
// sigc::track_obj().
153-
sigc::slot<void(std::ostringstream&)> sl10;
158+
// sigc::track_obj() or sigc::track_object().
159+
sigc::slot<void(std::ostringstream&)> sl11;
160+
sigc::slot<void(std::ostringstream&)> sl12;
154161
{
155162
book guest_book("karl");
156-
// sl1 = [&guest_book](std::ostringstream& stream){ stream << guest_book << "\n"; }; // no
157-
// auto-disconnect
158-
sl10 = sigc::track_obj(
163+
// no auto-disconnect
164+
// sl1 = [&guest_book](std::ostringstream& stream){ stream << guest_book << "\n"; };
165+
sl11 = sigc::track_obj(
166+
[&guest_book](std::ostringstream& stream) { stream << guest_book; }, guest_book);
167+
sl12 = sigc::track_object(
159168
[&guest_book](std::ostringstream& stream) { stream << guest_book; }, guest_book);
160-
sl10(result_stream);
161-
util->check_result(result_stream, "karl");
169+
sl11(result_stream);
170+
sl12(result_stream);
171+
util->check_result(result_stream, "karlkarl");
162172

163-
} // auto-disconnect sl10
173+
} // auto-disconnect sl11 and sl12
164174

165-
sl10(result_stream);
175+
sl11(result_stream);
176+
sl12(result_stream);
166177
util->check_result(result_stream, "");
167178

168179
// auto-disconnect
169-
sigc::slot<void()> sl20;
180+
sigc::slot<void()> sl21;
181+
sigc::slot<void()> sl22;
170182
{
171183
book guest_book("karl");
172184
// sl2 = [&guest_book] () { egon(guest_book); }; // no auto-disconnect
173185
// sl2 = std::bind(&egon, std::ref(guest_book)); // does not compile (gcc 4.6.3)
174-
sl20 = sigc::track_obj([&guest_book]() { egon(guest_book); }, guest_book);
175-
sl20();
176-
util->check_result(result_stream, "egon(string 'karl')");
186+
sl21 = sigc::track_obj([&guest_book]() { egon(guest_book); }, guest_book);
187+
sl22 = sigc::track_obj([&guest_book]() { egon(guest_book); }, guest_book);
188+
sl21();
189+
sl22();
190+
util->check_result(result_stream, "egon(string 'karl')egon(string 'egon was here')");
177191

178192
result_stream << static_cast<const std::string&>(guest_book);
179193
util->check_result(result_stream, "egon was here");
180194

181-
} // auto-disconnect sl20
195+
} // auto-disconnect sl21 and sl22
182196

183-
sl20();
197+
sl21();
198+
sl22();
184199
util->check_result(result_stream, "");
185200

186201
// Code example in the documentation sigc++/adaptors/track_obj.h.
@@ -194,8 +209,9 @@ main(int argc, char* argv[])
194209
// some_signal.connect(sigc::bind(&foo_group4, std::ref(some_bar))); // auto-disconnects,
195210
// but we prefer C++11 lambda
196211
some_signal.connect(sigc::track_obj([&some_bar]() { foo_group4(some_bar); }, some_bar));
212+
some_signal.connect(sigc::track_object([&some_bar]() { foo_group4(some_bar); }, some_bar));
197213
some_signal.emit();
198-
util->check_result(result_stream, "foo_group4(bar_group4&)");
214+
util->check_result(result_stream, "foo_group4(bar_group4&)foo_group4(bar_group4&)");
199215

200216
} // auto-disconnect the lambda expression
201217

0 commit comments

Comments
 (0)