diff options
author | Kjell Ahlstedt <kjell.ahlstedt@bredband.net> | 2013-02-26 09:29:34 +0100 |
---|---|---|
committer | Kjell Ahlstedt <kjell.ahlstedt@bredband.net> | 2013-02-26 09:29:34 +0100 |
commit | b0727f4e8cbb289d66b11fc29adf133f6c86847e (patch) | |
tree | 46191fbeb400c8fe00b36d632c14fd540eaca167 | |
parent | 7c6ff314507bd0beb3b92ebf0a0f6258b67d7796 (diff) | |
download | sigc++-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-- | ChangeLog | 17 | ||||
-rw-r--r-- | sigc++/.gitignore | 1 | ||||
-rw-r--r-- | sigc++/adaptors/adaptors.h | 1 | ||||
-rw-r--r-- | sigc++/adaptors/lambda/macros/group.h.m4 | 19 | ||||
-rw-r--r-- | sigc++/adaptors/macros/adaptor_trait.h.m4 | 5 | ||||
-rw-r--r-- | sigc++/adaptors/macros/track_obj.h.m4 | 218 | ||||
-rw-r--r-- | sigc++/filelist.am | 6 | ||||
-rw-r--r-- | tests/.gitignore | 1 | ||||
-rw-r--r-- | tests/Makefile.am | 4 | ||||
-rw-r--r-- | tests/test_cpp11_lambda.cc | 30 | ||||
-rw-r--r-- | tests/test_track_obj.cc | 230 |
11 files changed, 498 insertions, 34 deletions
@@ -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; +} |