1 /* Copyright (C) 2016 Murray Cumming
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/
19 #include <sigc++/tuple-utils/tuple_transform_each.h>
23 template <class T_element_from>
24 class transform_to_string {
27 transform(T_element_from& from) {
28 return std::to_string(from);
32 // In these tests, t_expected has elements all of the same type.
34 test_tuple_transform_each_same_types() {
36 auto t_original = std::make_tuple(1, 2, 3);
38 sigc::internal::tuple_transform_each<transform_to_string>(t_original);
40 std::make_tuple(std::string("1"), std::string("2"), std::string("3"));
42 static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
43 "unexpected tuple_transform_each()ed tuple size.");
45 assert(std::get<0>(t_transformed) == "1");
46 assert(std::get<1>(t_transformed) == "2");
47 assert(std::get<2>(t_transformed) == "3");
50 std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
51 "unexpected transform_each()ed tuple type");
55 auto t_original = std::make_tuple(1, (double)2.1f, 3);
57 sigc::internal::tuple_transform_each<transform_to_string>(t_original);
59 std::make_tuple(std::string("1"), std::string("2"), std::string("3"));
61 static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
62 "unexpected tuple_transform_each()ed tuple size.");
64 assert(std::get<0>(t_transformed) == "1");
65 assert(std::get<1>(t_transformed).substr(0, 3) == "2.1");
66 assert(std::get<2>(t_transformed) == "3");
69 std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
70 "unexpected transform_each()ed tuple type");
74 // The general template declaration.
75 // We then provide specializations for each type,
76 // so we can test having a different return value for each T_element_from type.
77 template <class T_element_from>
78 class transform_to_something;
80 // An int will be converted to a std::string:
82 class transform_to_something<int> {
85 transform(int& from) {
86 return std::to_string(from);
90 // A double will be converted to a char:
92 class transform_to_something<double> {
95 transform(double& from) {
96 return std::to_string(from)[0];
100 // A std::string will be converted to an int:
102 class transform_to_something<std::string> {
105 transform(std::string& from) {
106 return std::stoi(from);
110 // In these tests, t_expected has elements of different types.
112 test_tuple_transform_each_multiple_types() {
113 auto t_original = std::make_tuple(1, (double)2.1f, std::string("3"));
115 sigc::internal::tuple_transform_each<transform_to_something>(t_original);
116 auto t_expected = std::make_tuple(std::string("1"), '2', 3);
118 static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
119 "unexpected tuple_transform_each()ed tuple size.");
121 assert(std::get<0>(t_transformed) == "1");
122 assert(std::get<1>(t_transformed) == '2');
123 assert(std::get<2>(t_transformed) == 3);
126 std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
127 "unexpected transform_each()ed tuple type");
130 template <class T_element_from>
131 class transform_each_nonconst {
134 transform(T_element_from& from) {
136 // Or, for instance, call a non-const method on from.
143 test_tuple_transform_each_nonconst() {
144 auto t = std::make_tuple(1, 2, 3);
146 sigc::internal::tuple_transform_each<transform_each_nonconst>(t);
148 // Check that t was changed (from * 2):
149 assert(std::get<0>(t) == 2);
150 assert(std::get<1>(t) == 4);
151 assert(std::get<2>(t) == 6);
153 // Check that t_transformed has the expected values ( from * 2 * 10):
154 assert(std::get<0>(t_transformed) == 20);
155 assert(std::get<1>(t_transformed) == 40);
156 assert(std::get<2>(t_transformed) == 60);
160 test_tuple_transform_each_stdref() {
164 auto t_original = std::make_tuple(std::ref(a), std::ref(b), std::ref(c));
166 sigc::internal::tuple_transform_each<transform_to_string>(t_original);
168 std::make_tuple(std::string("1"), std::string("2"), std::string("3"));
170 static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
171 "unexpected tuple_transform_each()ed tuple size.");
173 assert(std::get<0>(t_transformed) == "1");
174 assert(std::get<1>(t_transformed) == "2");
175 assert(std::get<2>(t_transformed) == "3");
178 std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
179 "unexpected transform_each()ed tuple type");
183 //This can only be used via std::ref(), for instance.
184 //Any attempt to copy or move it, should cause a compiler error.
187 explicit NonCopyable(int val)
191 int get_val() const {
195 NonCopyable(const NonCopyable& src) = delete;
196 NonCopyable& operator=(const NonCopyable& src) = delete;
198 NonCopyable(NonCopyable&& src) = delete;
199 NonCopyable& operator=(NonCopyable&& src) = delete;
206 template <class T_element_from>
207 class transform_noncopyable_to_string {
209 static decltype(auto)
210 transform(T_element_from&& from) {
211 return std::to_string(from.get_val());
216 test_tuple_transform_each_stdref_non_copyable() {
220 auto t_original = std::make_tuple(std::ref(a), std::ref(b), std::ref(c));
222 sigc::internal::tuple_transform_each<transform_noncopyable_to_string>(t_original);
224 std::make_tuple(std::string("1"), std::string("2"), std::string("3"));
226 static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
227 "unexpected tuple_transform_each()ed tuple size.");
229 assert(std::get<0>(t_transformed) == "1");
230 assert(std::get<1>(t_transformed) == "2");
231 assert(std::get<2>(t_transformed) == "3");
234 std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
235 "unexpected transform_each()ed tuple type");
238 static std::string correct_sequence_output;
240 template <class T_element_from>
241 class transform_each_correct_sequence {
243 static decltype(auto)
244 transform(int from) {
245 correct_sequence_output += std::to_string(from);
246 return std::to_string(from);
251 test_tuple_transform_each_correct_sequence() {
252 correct_sequence_output.clear();
253 auto t = std::make_tuple(1, 2, 3);
254 sigc::internal::tuple_transform_each<transform_each_correct_sequence>(t);
255 //std::cout << "correct_sequence_output: " << correct_sequence_output << std::endl;
256 assert(correct_sequence_output == "123");
260 test_tuple_transform_each_empty_tuple() {
261 auto t = std::tuple<>();
262 sigc::internal::tuple_transform_each<transform_to_string>(t);
265 // The general template declaration.
266 // We then provide specializations for each type,
267 // so we can test having a different return value for each T_element_from type.
268 template <class T_element_from>
269 class transform_as_constexpr_to_something;
271 // An int will be converted to a char:
273 class transform_as_constexpr_to_something<int> {
278 transform(int from) {
283 // A double will be converted to an int:
285 class transform_as_constexpr_to_something<const double> {
290 transform(double from) {
295 /* TODO: See the comment in main().
298 test_tuple_transform_each_constexpr() {
299 constexpr auto t_original = std::make_tuple(1, (double)2.1f);
300 constexpr auto t_transformed =
301 sigc::internal::tuple_transform_each<transform_as_constexpr_to_something>(t_original);
302 constexpr auto t_expected = std::make_tuple('b', 2);
304 static_assert(std::tuple_size<decltype(t_transformed)>::value == 2,
305 "unexpected tuple_transform_each()ed tuple size.");
307 assert(std::get<0>(t_transformed) == 'b');
308 assert(std::get<1>(t_transformed) == 2);
311 std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
312 "unexpected transform_each()ed tuple type");
318 test_tuple_transform_each_same_types();
319 test_tuple_transform_each_multiple_types();
321 test_tuple_transform_each_nonconst();
323 test_tuple_transform_each_stdref();
324 test_tuple_transform_each_stdref_non_copyable();
326 test_tuple_transform_each_correct_sequence();
328 test_tuple_transform_each_empty_tuple();
330 // g++ 5.2.1 gives this error:
331 // error: accessing uninitialized member ‘std::tuple<char>::<anonymous>’
332 // though it works with clang++.
333 // TODO: Try it with a newer g++.
334 //test_tuple_transform_each_constexpr();