]> git.tdb.fi Git - ext/sigc++-2.0.git/blob - tests/test_track_obj.cc
Adjust the name of the library to match upstream
[ext/sigc++-2.0.git] / tests / test_track_obj.cc
1 /* Copyright (C) 2013 The libsigc++ Development Team
2  *
3  * This file is part of libsigc++.
4  *
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.
9  *
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.
14  *
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/>.
17  */
18
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 shows that C++11 lambda expressions can replace the libsigc++ lambda
25 //   expressions, which have been removed.
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.
28 //
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 $?
34 // If test_track_obj writes nothing and the return code is 0, the test has passed.
35
36
37 #include "testutilities.h"
38 #include <string>
39 #include <iostream>
40 #include <sstream>
41 #include <cstdlib>
42 #include <sigc++/adaptors/track_obj.h>
43 #include <sigc++/signal.h>
44
45
46 namespace
47 {
48 std::ostringstream result_stream;
49
50 struct book : public sigc::trackable
51 {
52   explicit book(const std::string& name) : name_(name) {}
53   operator std::string& () { return name_; }
54   operator const std::string& () const { return name_; }
55   std::string name_;
56 };
57
58 struct bar_group4 : public sigc::trackable
59 {
60 };
61
62 class Functor1 : public sigc::functor_base
63 {
64 public:
65   typedef std::string result_type;
66
67   Functor1(const bar_group4& bar)
68   : bar_(bar) {}
69
70   std::string operator()(int i)
71   {
72     return (i<0) ? "negative" : ((i>0) ? "positive" : "zero");
73   }
74
75 protected:
76   // Don't make it private. clang++ does not like unused private data.
77   const bar_group4& bar_;
78 };
79
80 class Functor2 : public sigc::functor_base
81 {
82 public:
83   typedef std::string result_type;
84
85   Functor2(const bar_group4& bar, const book& aBook)
86   : bar_(bar), aBook_(aBook) {}
87
88   std::string operator()(int i, const std::string& str) const
89   {
90     std::string result = (i<0) ? "negative, " : ((i>0) ? "positive, " : "zero, ");
91     result += str;
92     result += aBook_;
93     return result;
94   }
95
96 protected:
97   // Don't make it private. clang++ does not like unused private data.
98   const bar_group4& bar_;
99 private:
100   const book& aBook_;
101 };
102
103 //C++11 lamba expressions:
104
105 inline std::ostringstream& operator << (std::ostringstream& s, const book& b)
106 {
107   s << b.name_;
108   return s;
109 }
110
111 void egon(std::string& str)
112 {
113   result_stream << "egon(string '" << str << "')";
114   str = "egon was here";
115 }
116
117 void foo_group4(bar_group4&)
118 {
119   result_stream << "foo_group4(bar_group4&)";
120 }
121
122 } // end anonymous namespace
123
124
125 int main(int argc, char* argv[])
126 {
127   auto util = TestUtilities::get_instance();
128
129   if (!util->check_command_args(argc, argv))
130     return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
131
132   sigc::slot<std::string, int> sl1;
133   {
134     bar_group4 bar4;
135     sl1 = sigc::track_obj(Functor1(bar4), bar4);
136     result_stream << sl1(-2);
137     util->check_result(result_stream, "negative");
138
139   } // auto-disconnect sl1
140
141   result_stream << sl1(-2);
142   util->check_result(result_stream, "");
143
144   // Allocate on the heap. valgrind can then find erroneous memory accesses.
145   // (There should be none, of course.)
146   auto psl2 = new sigc::slot<std::string, int, std::string>;
147   bar_group4* pbar4 = new bar_group4;
148   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");
152
153   delete pbook4; // auto-disconnect *psl2
154   pbook4 = nullptr;
155   result_stream << (*psl2)(0, "Book title: ");
156   util->check_result(result_stream, "");
157   delete psl2;
158   psl2 = nullptr;
159   delete pbar4;
160   pbar4 = nullptr;
161
162
163 //C++11 lambda expressions:
164
165   // auto-disconnect
166   // If you want to auto-disconnect a slot with a C++11 lambda expression
167   // that contains references to sigc::trackable-derived objects, you must use
168   // sigc::track_obj().
169   sigc::slot<void, std::ostringstream&> sl10;
170   {
171     book guest_book("karl");
172     // 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);
180   util->check_result(result_stream, "");
181
182   // auto-disconnect
183   sigc::slot<void> sl20;
184   {
185     book guest_book("karl");
186     // sl2 = [&guest_book] () { egon(guest_book); }; // no auto-disconnect
187     // 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')");
191
192     result_stream << static_cast<const std::string&>(guest_book);
193     util->check_result(result_stream, "egon was here");
194
195   } // auto-disconnect sl20
196
197   sl20();
198   util->check_result(result_stream, "");
199
200
201   // Code example in the documentation sigc++/adaptors/macros/track_obj.h.m4
202   // -----------------------------------------------------------------------
203   {
204     //struct bar : public sigc::trackable {} some_bar;
205     sigc::signal<void> some_signal;
206     {
207       bar_group4 some_bar;
208       //some_signal.connect(sigc::group(&foo,std::ref(some_bar)));
209       // disconnected automatically if some_bar goes out of scope
210       //some_signal.connect([&some_bar](){ foo_group4(some_bar); }); // no auto-disconnect
211       //some_signal.connect(sigc::bind(&foo_group4, std::ref(some_bar))); // auto-disconnects, but we prefer C++11 lambda
212       some_signal.connect(sigc::track_obj([&some_bar](){ foo_group4(some_bar); }, some_bar));
213       some_signal.emit();
214       util->check_result(result_stream, "foo_group4(bar_group4&)");
215
216     } // auto-disconnect the lambda expression
217
218     some_signal.emit();
219     util->check_result(result_stream, "");
220   }
221
222
223   return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
224 }