Skip to content

Commit e51bf59

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

File tree

2 files changed

+87
-50
lines changed

2 files changed

+87
-50
lines changed

sigc++/adaptors/macros/track_obj.h.m4

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ FOR(1, $1,[
5050
dnl track_obj_functor[2..CALL_SIZE]. $1 is assumed to be >= 2.
5151
define([TRACK_OBJECT_FUNCTOR],[dnl
5252
/** track_obj_functor$1 wraps a functor and stores $1 references to trackable objects.
53-
* Use the convenience function track_obj() to create an instance of track_obj_functor$1.
53+
* Use the convenience function track_object() to create an instance of track_obj_functor$1.
5454
*
5555
* @tparam T_functor The type of functor to wrap.dnl
5656
FOR(1,$1,[
@@ -111,13 +111,15 @@ FOR(1,$1,[
111111
])dnl end TRACK_OBJECT_VISIT_EACH
112112

113113
define([TRACK_OBJECT],[dnl
114+
_DEPRECATE_IFDEF_START
114115
/** Creates an adaptor of type sigc::track_obj_functor$1 which wraps a functor.
115116
* @param _A_func Functor that shall be wrapped.dnl
116117
FOR(1,$1,[
117118
* @param _A_obj%1 Trackable object.])
118119
* @return Adaptor that executes _A_func() on invocation.
119120
*
120121
* @newin{2,4}
122+
* @deprecated Use sigc::track_object() instead.
121123
*
122124
* @ingroup track_obj
123125
*/
@@ -128,26 +130,54 @@ track_obj(const T_functor& _A_func, LOOP(const T_obj%1& _A_obj%1, $1))
128130
return track_obj_functor$1<T_functor, LOOP(T_obj%1, $1)>
129131
(_A_func, LOOP(_A_obj%1, $1));
130132
}
133+
_DEPRECATE_IFDEF_END
131134
132135
])dnl end TRACK_OBJECT
133136

137+
define([TRACK_OBJECT2],[dnl
138+
/** Creates an adaptor of type sigc::track_obj_functor$1 which wraps a functor.
139+
* @param _A_func Functor that shall be wrapped.dnl
140+
FOR(1,$1,[[
141+
* @param _A_obj%1 Trackable object, derived directly or indirectly from sigc::trackable.]])
142+
* @return Adaptor that executes _A_func() on invocation.
143+
*
144+
* @newin{2,12}
145+
*
146+
* @ingroup track_obj
147+
*/
148+
template <typename T_functor, LOOP(typename T_obj%1, $1)>
149+
inline track_obj_functor$1<T_functor, LOOP(T_obj%1, $1)>
150+
track_object(const T_functor& _A_func, LOOP(const T_obj%1& _A_obj%1, $1))
151+
{
152+
static_assert(LOOP([[std::is_base_of<sigc::trackable, T_obj%1>::value]], $1, [ && ]),
153+
"Each trackable object must be derived from sigc::trackable.");
154+
155+
return track_obj_functor$1<T_functor, LOOP(T_obj%1, $1)>
156+
(_A_func, LOOP(_A_obj%1, $1));
157+
}
158+
159+
])dnl end TRACK_OBJECT2
160+
134161
divert(0)dnl
135162
_FIREWALL([ADAPTORS_TRACK_OBJ])
136163
#include <sigc++/adaptors/adaptor_trait.h>
137164
#include <sigc++/limit_reference.h>
165+
#include <type_traits>
138166

139167
namespace sigc {
140168

141-
/** @defgroup track_obj track_obj()
142-
* sigc::track_obj() tracks trackable objects, referenced from a functor.
169+
/** @defgroup track_obj track_obj(), track_object()
170+
* sigc::track_object() tracks trackable objects, referenced from a functor.
143171
* It can be useful when you assign a C++11 lambda expression or a std::function<>
144172
* to a slot, or connect it to a signal, and the lambda expression or std::function<>
145173
* contains references to sigc::trackable derived objects.
146174
*
147-
* The functor returned by sigc::track_obj() is formally an adaptor, but it does
175+
* The functor returned by sigc::track_object() is formally an adaptor, but it does
148176
* not alter the signature, return type or behaviour of the supplied functor.
149177
* Up to CALL_SIZE objects can be tracked. operator()() can have up to CALL_SIZE arguments.
150178
*
179+
* track_obj() is a deprecated alternative to track_object().
180+
*
151181
* @par Example:
152182
* @code
153183
* struct bar : public sigc::trackable {};
@@ -157,18 +187,16 @@ namespace sigc {
157187
* bar some_bar;
158188
* some_signal.connect([[&some_bar]](){ foo(some_bar); });
159189
* // NOT disconnected automatically when some_bar goes out of scope
160-
* some_signal.connect(sigc::track_obj([[&some_bar]](){ foo(some_bar); }, some_bar);
190+
* some_signal.connect(sigc::track_object([[&some_bar]](){ foo(some_bar); }, some_bar);
161191
* // disconnected automatically when some_bar goes out of scope
162192
* }
163193
* @endcode
164194
*
165-
* @newin{2,4}
166-
*
167195
* @ingroup adaptors
168196
*/
169197

170198
/** track_obj_functor1 wraps a functor and stores a reference to a trackable object.
171-
* Use the convenience function track_obj() to create an instance of track_obj_functor1.
199+
* Use the convenience function track_object() to create an instance of track_obj_functor1.
172200
*
173201
* @tparam T_functor The type of functor to wrap.
174202
* @tparam T_obj1 The type of a trackable object.
@@ -221,5 +249,6 @@ FOR(1,CALL_SIZE,[[TRACK_OBJECT_VISIT_EACH(%1)]])dnl
221249
#endif // DOXYGEN_SHOULD_SKIP_THIS
222250

223251
FOR(1,CALL_SIZE,[[TRACK_OBJECT(%1)]])dnl
252+
FOR(1,CALL_SIZE,[[TRACK_OBJECT2(%1)]])dnl
224253

225254
} /* namespace sigc */

tests/test_track_obj.cc

Lines changed: 50 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,17 @@
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
2727
// - Test the code example in the documentation in sigc++/adaptors/track_obj.h.
2828
//
29-
// To test the C++11 lambda expressions with gcc 4.6.3 (and probably some later
30-
// versions of gcc; gcc 4.7.x also understands -std=c++11):
31-
// make CXXFLAGS='-g -O2 -std=c++0x' test_track_obj
32-
// ./test_track_obj
33-
// echo $?
3429
// If test_track_obj writes nothing and the return code is 0, the test has passed.
3530

36-
3731
#include "testutilities.h"
3832
#include <string>
3933
#include <iostream>
@@ -130,74 +124,88 @@ int main(int argc, char* argv[])
130124
return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
131125

132126
sigc::slot<std::string, int> sl1;
127+
sigc::slot<std::string, int> sl2;
133128
{
134129
bar_group4 bar4;
135130
sl1 = sigc::track_obj(Functor1(bar4), bar4);
136-
result_stream << sl1(-2);
137-
util->check_result(result_stream, "negative");
131+
sl2 = sigc::track_object(Functor1(bar4), bar4);
132+
result_stream << sl1(-2) << ", " << sl2(2);
133+
util->check_result(result_stream, "negative, positive");
138134

139-
} // auto-disconnect sl1
135+
} // auto-disconnect sl1 and sl2
140136

141-
result_stream << sl1(-2);
142-
util->check_result(result_stream, "");
137+
result_stream << sl1(-2) << ", " << sl2(2);
138+
util->check_result(result_stream, ", ");
143139

144140
// Allocate on the heap. valgrind can then find erroneous memory accesses.
145141
// (There should be none, of course.)
146-
auto psl2 = new sigc::slot<std::string, int, std::string>;
142+
auto psl3 = new sigc::slot<std::string, int, std::string>;
143+
auto psl4 = new sigc::slot<std::string, int, std::string>;
147144
bar_group4* pbar4 = new bar_group4;
148145
book* pbook4 = new book("A Book");
149-
*psl2 = sigc::track_obj(Functor2(*pbar4, *pbook4), *pbar4, *pbook4);
150-
result_stream << (*psl2)(0, "Book title: ");
151-
util->check_result(result_stream, "zero, Book title: A Book");
146+
*psl3 = sigc::track_obj(Functor2(*pbar4, *pbook4), *pbar4, *pbook4);
147+
*psl4 = sigc::track_object(Functor2(*pbar4, *pbook4), *pbar4, *pbook4);
148+
result_stream << (*psl3)(0, "Book title: ") << ", " << (*psl4)(1, "Title: ");
149+
util->check_result(result_stream, "zero, Book title: A Book, positive, Title: A Book");
152150

153-
delete pbook4; // auto-disconnect *psl2
151+
delete pbook4; // auto-disconnect *psl3 and *psl4
154152
pbook4 = nullptr;
155-
result_stream << (*psl2)(0, "Book title: ");
156-
util->check_result(result_stream, "");
157-
delete psl2;
158-
psl2 = nullptr;
153+
result_stream << (*psl3)(0, "Book title: ") << ", " << (*psl4)(1, "Title: ");
154+
util->check_result(result_stream, ", ");
155+
delete psl3;
156+
psl3 = nullptr;
157+
delete psl4;
158+
psl4 = nullptr;
159159
delete pbar4;
160160
pbar4 = nullptr;
161161

162-
163-
//C++11 lambda expressions:
162+
// C++11 lambda expressions:
164163

165164
// auto-disconnect
166165
// If you want to auto-disconnect a slot with a C++11 lambda expression
167166
// that contains references to sigc::trackable-derived objects, you must use
168-
// sigc::track_obj().
169-
sigc::slot<void, std::ostringstream&> sl10;
167+
// sigc::track_obj() or sigc::track_object().
168+
sigc::slot<void, std::ostringstream&> sl11;
169+
sigc::slot<void, std::ostringstream&> sl12;
170170
{
171171
book guest_book("karl");
172172
// sl1 = [&guest_book](std::ostringstream& stream){ stream << guest_book << "\n"; }; // no auto-disconnect
173-
sl10 = sigc::track_obj([&guest_book](std::ostringstream& stream){ stream << guest_book; }, guest_book);
174-
sl10(result_stream);
175-
util->check_result(result_stream, "karl");
176-
177-
} // auto-disconnect sl10
178-
179-
sl10(result_stream);
173+
sl11 = sigc::track_obj(
174+
[&guest_book](std::ostringstream& stream) { stream << guest_book; }, guest_book);
175+
sl12 = sigc::track_object(
176+
[&guest_book](std::ostringstream& stream) { stream << guest_book; }, guest_book);
177+
sl11(result_stream);
178+
sl12(result_stream);
179+
util->check_result(result_stream, "karlkarl");
180+
181+
} // auto-disconnect sl11 and sl12
182+
183+
sl11(result_stream);
184+
sl12(result_stream);
180185
util->check_result(result_stream, "");
181186

182187
// auto-disconnect
183-
sigc::slot<void> sl20;
188+
sigc::slot<void> sl21;
189+
sigc::slot<void> sl22;
184190
{
185191
book guest_book("karl");
186192
// sl2 = [&guest_book] () { egon(guest_book); }; // no auto-disconnect
187193
// sl2 = std::bind(&egon, std::ref(guest_book)); // does not compile (gcc 4.6.3)
188-
sl20 = sigc::track_obj([&guest_book] () { egon(guest_book); }, guest_book);
189-
sl20();
190-
util->check_result(result_stream, "egon(string 'karl')");
194+
sl21 = sigc::track_obj([&guest_book]() { egon(guest_book); }, guest_book);
195+
sl22 = sigc::track_obj([&guest_book]() { egon(guest_book); }, guest_book);
196+
sl21();
197+
sl22();
198+
util->check_result(result_stream, "egon(string 'karl')egon(string 'egon was here')");
191199

192200
result_stream << static_cast<const std::string&>(guest_book);
193201
util->check_result(result_stream, "egon was here");
194202

195-
} // auto-disconnect sl20
203+
} // auto-disconnect sl21 and sl22
196204

197-
sl20();
205+
sl21();
206+
sl22();
198207
util->check_result(result_stream, "");
199208

200-
201209
// Code example in the documentation sigc++/adaptors/macros/track_obj.h.m4
202210
// -----------------------------------------------------------------------
203211
{
@@ -210,15 +218,15 @@ int main(int argc, char* argv[])
210218
//some_signal.connect([&some_bar](){ foo_group4(some_bar); }); // no auto-disconnect
211219
//some_signal.connect(sigc::bind(&foo_group4, std::ref(some_bar))); // auto-disconnects, but we prefer C++11 lambda
212220
some_signal.connect(sigc::track_obj([&some_bar](){ foo_group4(some_bar); }, some_bar));
221+
some_signal.connect(sigc::track_object([&some_bar](){ foo_group4(some_bar); }, some_bar));
213222
some_signal.emit();
214-
util->check_result(result_stream, "foo_group4(bar_group4&)");
223+
util->check_result(result_stream, "foo_group4(bar_group4&)foo_group4(bar_group4&)");
215224

216225
} // auto-disconnect the lambda expression
217226

218227
some_signal.emit();
219228
util->check_result(result_stream, "");
220229
}
221230

222-
223231
return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
224232
}

0 commit comments

Comments
 (0)