1 /* Copyright (C) 2013 The libsigc++ Development Team
3 * This file is part of libsigc++.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 // The purpose of this test case is threefold.
20 // - Test sigc::track_obj().
21 // - Show that a slot with a C++11 lambda expression can be automatically
22 // disconnected when an object derived from sigc::trackable is deleted,
23 // provided sigc::track_obj() is used.
24 // It's shown here as a preparation for deprecating and eventually
25 // deleting the libsigc++ lambda expressions.
26 // See https://bugzilla.gnome.org/show_bug.cgi?id=672555
27 // - Test the code example in the documentation in sigc++/adaptors/track_obj.h.
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
34 // If test_track_obj writes nothing and the return code is 0, the test has passed.
37 #include "testutilities.h"
42 #include <sigc++/adaptors/track_obj.h>
43 #include <sigc++/signal.h>
48 std::ostringstream result_stream;
50 struct book : public sigc::trackable
52 explicit book(const std::string& name) : name_(name) {}
53 operator std::string& () { return name_; }
54 operator const std::string& () const { return name_; }
58 struct bar_group4 : public sigc::trackable
62 class Functor1 : public sigc::functor_base
65 using result_type = std::string;
67 Functor1(const bar_group4& bar)
70 std::string operator()(int i)
72 return (i<0) ? "negative" : ((i>0) ? "positive" : "zero");
76 const bar_group4& bar_;
79 class Functor2 : public sigc::functor_base
82 using result_type = std::string;
84 Functor2(const bar_group4& bar, const book& aBook)
85 : bar_(bar), aBook_(aBook) {}
87 std::string operator()(int i, const std::string& str) const
89 std::string result = (i<0) ? "negative, " : ((i>0) ? "positive, " : "zero, ");
96 const bar_group4& bar_;
100 //C++11 lamba expressions:
102 inline std::ostringstream& operator << (std::ostringstream& s, const book& b)
108 void egon(std::string& str)
110 result_stream << "egon(string '" << str << "')";
111 str = "egon was here";
114 void foo_group4(bar_group4&)
116 result_stream << "foo_group4(bar_group4&)";
119 } // end anonymous namespace
122 int main(int argc, char* argv[])
124 auto util = TestUtilities::get_instance();
126 if (!util->check_command_args(argc, argv))
127 return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
129 sigc::slot<std::string(int)> sl1;
132 sl1 = sigc::track_obj(Functor1(bar4), bar4);
133 result_stream << sl1(-2);
134 util->check_result(result_stream, "negative");
136 } // auto-disconnect sl1
138 result_stream << sl1(-2);
139 util->check_result(result_stream, "");
141 // Allocate on the heap. valgrind can then find erroneous memory accesses.
142 // (There should be none, of course.)
143 auto psl2 = new sigc::slot<std::string(int, std::string)>;
144 bar_group4* pbar4 = new bar_group4;
145 book* pbook4 = new book("A Book");
146 *psl2 = sigc::track_obj(Functor2(*pbar4, *pbook4), *pbar4, *pbook4);
147 result_stream << (*psl2)(0, "Book title: ");
148 util->check_result(result_stream, "zero, Book title: A Book");
150 delete pbook4; // auto-disconnect *psl2
152 result_stream << (*psl2)(0, "Book title: ");
153 util->check_result(result_stream, "");
160 //C++11 lambda expressions:
163 // If you want to auto-disconnect a slot with a C++11 lambda expression
164 // that contains references to sigc::trackable-derived objects, you must use
165 // sigc::track_obj().
166 sigc::slot<void(std::ostringstream&)> sl10;
168 book guest_book("karl");
169 // sl1 = [&guest_book](std::ostringstream& stream){ stream << guest_book << "\n"; }; // no auto-disconnect
170 sl10 = sigc::track_obj([&guest_book](std::ostringstream& stream){ stream << guest_book; }, guest_book);
172 util->check_result(result_stream, "karl");
174 } // auto-disconnect sl10
177 util->check_result(result_stream, "");
180 sigc::slot<void()> sl20;
182 book guest_book("karl");
183 // sl2 = [&guest_book] () { egon(guest_book); }; // no auto-disconnect
184 // sl2 = std::bind(&egon, std::ref(guest_book)); // does not compile (gcc 4.6.3)
185 sl20 = sigc::track_obj([&guest_book] () { egon(guest_book); }, guest_book);
187 util->check_result(result_stream, "egon(string 'karl')");
189 result_stream << static_cast<const std::string&>(guest_book);
190 util->check_result(result_stream, "egon was here");
192 } // auto-disconnect sl20
195 util->check_result(result_stream, "");
198 // Code example in the documentation sigc++/adaptors/macros/track_obj.h.m4
199 // -----------------------------------------------------------------------
201 //struct bar : public sigc::trackable {} some_bar;
202 sigc::signal<void()> some_signal;
205 //some_signal.connect(sigc::group(&foo, std::ref(some_bar)));
206 // disconnected automatically if some_bar goes out of scope
207 //some_signal.connect([&some_bar](){ foo_group4(some_bar); }); // no auto-disconnect
208 //some_signal.connect(sigc::bind(&foo_group4, std::ref(some_bar))); // auto-disconnects, but we prefer C++11 lambda
209 some_signal.connect(sigc::track_obj([&some_bar](){ foo_group4(some_bar); }, some_bar));
211 util->check_result(result_stream, "foo_group4(bar_group4&)");
213 } // auto-disconnect the lambda expression
216 util->check_result(result_stream, "");
220 return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;