1 //-----------------------------------------------------------------------------
2 // boost-libs variant/test/auto_visitors.cpp source file
3 // See http://www.boost.org for updates, documentation, and revision history.
4 //-----------------------------------------------------------------------------
5 //
6 // Copyright (c) 2014-2021 Antony Polukhin
7 //
8 // Distributed under the Boost Software License, Version 1.0. (See
9 // accompanying file LICENSE_1_0.txt or copy at
10 // http://www.boost.org/LICENSE_1_0.txt)
11 
12 #include "boost/config.hpp"
13 
14 #include "boost/core/lightweight_test.hpp"
15 #include "boost/variant.hpp"
16 #include "boost/variant/multivisitors.hpp"
17 #include "boost/lexical_cast.hpp"
18 
19 #include <boost/noncopyable.hpp>
20 #include <boost/core/ignore_unused.hpp>
21 
22 namespace has_result_type_tests {
23     template <class T>
24     struct wrap {
25         typedef T result_type;
26     };
27 
28     struct s1 : wrap<int> {};
29     struct s2 : wrap<int&> {};
30     struct s3 : wrap<const int&> {};
31     struct s4 {};
32     struct s5 : wrap<int*> {};
33     struct s6 : wrap<int**> {};
34     struct s7 : wrap<const int*> {};
35     struct s8 : wrap<boost::noncopyable> {};
36     struct s9 : wrap<boost::noncopyable&> {};
37 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
38     struct s10 : wrap<boost::noncopyable&&> {};
39 #endif
40     struct s11 : wrap<const boost::noncopyable&> {};
41     struct s12 : wrap<const boost::noncopyable*> {};
42     struct s13 : wrap<boost::noncopyable*> {};
43     struct s14 { typedef int result_type; };
44     struct s15 { typedef int& result_type; };
45     struct s16 { typedef const int& result_type; };
46 }
47 
48 
test_has_result_type_triat()49 void test_has_result_type_triat() {
50     using namespace has_result_type_tests;
51     using boost::detail::variant::has_result_type;
52 
53     BOOST_TEST(has_result_type<s1>::value);
54     BOOST_TEST(has_result_type<s2>::value);
55     BOOST_TEST(has_result_type<s3>::value);
56     BOOST_TEST(!has_result_type<s4>::value);
57     BOOST_TEST(has_result_type<s5>::value);
58     BOOST_TEST(has_result_type<s6>::value);
59     BOOST_TEST(has_result_type<s7>::value);
60     BOOST_TEST(has_result_type<s8>::value);
61     BOOST_TEST(has_result_type<s9>::value);
62 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
63     BOOST_TEST(has_result_type<s10>::value);
64 #endif
65     BOOST_TEST(has_result_type<s11>::value);
66     BOOST_TEST(has_result_type<s12>::value);
67     BOOST_TEST(has_result_type<s13>::value);
68     BOOST_TEST(has_result_type<s14>::value);
69     BOOST_TEST(has_result_type<s15>::value);
70     BOOST_TEST(has_result_type<s16>::value);
71 }
72 
73 struct lex_streamer_explicit: boost::static_visitor<std::string> {
74     template <class T>
operator ()lex_streamer_explicit75     const char* operator()(const T& ) {
76         return "10";
77     }
78 
79     template <class T1, class T2>
operator ()lex_streamer_explicit80     const char* operator()(const T1& , const T2& ) {
81         return "100";
82     }
83 };
84 
85 
run_explicit()86 void run_explicit()
87 {
88     typedef boost::variant<int, std::string, double> variant_type;
89     variant_type v2("10"), v1("100");
90 
91     lex_streamer_explicit visitor_ref;
92 
93     // Must return instance of std::string
94     BOOST_TEST(boost::apply_visitor(visitor_ref, v2).c_str() == std::string("10"));
95     BOOST_TEST(boost::apply_visitor(visitor_ref, v2, v1).c_str() == std::string("100"));
96 }
97 
98 
99 // Most part of tests from this file require decltype(auto)
100 
101 #ifdef BOOST_NO_CXX14_DECLTYPE_AUTO
102 
run()103 void run()
104 {
105     BOOST_TEST(true);
106 }
107 
run2()108 void run2()
109 {
110     BOOST_TEST(true);
111 }
112 
113 
run3()114 void run3()
115 {
116     BOOST_TEST(true);
117 }
118 
119 #else
120 
121 #include <iostream>
122 
123 struct lex_streamer {
124     template <class T>
operator ()lex_streamer125     std::string operator()(const T& val) const {
126         return boost::lexical_cast<std::string>(val);
127     }
128 };
129 
130 struct lex_streamer_void {
131     template <class T>
operator ()lex_streamer_void132     void operator()(const T& val) const {
133         std::cout << val << std::endl;
134     }
135 
136 
137     template <class T1, class T2>
operator ()lex_streamer_void138     void operator()(const T1& val, const T2& val2) const {
139         std::cout << val << '+' << val2 << std::endl;
140     }
141 
142 
143     template <class T1, class T2, class T3>
operator ()lex_streamer_void144     void operator()(const T1& val, const T2& val2, const T3& val3) const {
145         std::cout << val << '+' << val2 << '+' << val3 << std::endl;
146     }
147 };
148 
149 
150 struct lex_streamer2 {
151     std::string res;
152 
153     template <class T>
operator ()lex_streamer2154     const char* operator()(const T& /*val*/) const {
155         return "fail";
156     }
157 
158     template <class T1, class T2>
operator ()lex_streamer2159     const char* operator()(const T1& /*v1*/, const T2& /*v2*/) const {
160         return "fail2";
161     }
162 
163 
164     template <class T1, class T2, class T3>
operator ()lex_streamer2165     const char* operator()(const T1& /*v1*/, const T2& /*v2*/, const T3& /*v3*/) const {
166         return "fail3";
167     }
168 
169     template <class T>
operator ()lex_streamer2170     std::string& operator()(const T& val) {
171         res = boost::lexical_cast<std::string>(val);
172         return res;
173     }
174 
175 
176     template <class T1, class T2>
operator ()lex_streamer2177     std::string& operator()(const T1& v1, const T2& v2) {
178         res = boost::lexical_cast<std::string>(v1) + "+" + boost::lexical_cast<std::string>(v2);
179         return res;
180     }
181 
182 
183     template <class T1, class T2, class T3>
operator ()lex_streamer2184     std::string& operator()(const T1& v1, const T2& v2, const T3& v3) {
185         res = boost::lexical_cast<std::string>(v1) + "+" + boost::lexical_cast<std::string>(v2)
186             + "+" + boost::lexical_cast<std::string>(v3);
187         return res;
188     }
189 };
190 
191 #ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES
192 #   define BOOST_TEST_IF_HAS_VARIADIC(x) BOOST_TEST(x)
193 #else
194 #   define BOOST_TEST_IF_HAS_VARIADIC(x) /**/
195 #endif
196 
run()197 void run()
198 {
199     typedef boost::variant<int, std::string, double> variant_type;
200     variant_type v1(1), v2("10"), v3(100.0);
201     lex_streamer lex_streamer_visitor;
202 
203     BOOST_TEST(boost::apply_visitor(lex_streamer(), v1) == "1");
204     BOOST_TEST_IF_HAS_VARIADIC(boost::apply_visitor(lex_streamer_visitor)(v1) == "1");
205     BOOST_TEST(boost::apply_visitor(lex_streamer(), v2) == "10");
206     BOOST_TEST_IF_HAS_VARIADIC(boost::apply_visitor(lex_streamer_visitor)(v2) == "10");
207 
208     #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS
209         BOOST_TEST(boost::apply_visitor([](auto v) { return boost::lexical_cast<std::string>(v); }, v1) == "1");
210         BOOST_TEST(boost::apply_visitor([](auto v) { return boost::lexical_cast<std::string>(v); }, v2) == "10");
211 
212         // Retun type must be the same in all instances, so this code does not compile
213         //boost::variant<int, short, unsigned> v_diff_types(1);
214         //BOOST_TEST(boost::apply_visitor([](auto v) { return v; }, v_diff_types) == 1);
215 
216         boost::apply_visitor([](auto v) { std::cout << v << std::endl; }, v1);
217         boost::apply_visitor([](auto v) { std::cout << v << std::endl; }, v2);
218     #endif
219 
220     lex_streamer2 visitor_ref;
221     BOOST_TEST(boost::apply_visitor(visitor_ref, v1) == "1");
222     BOOST_TEST(boost::apply_visitor(visitor_ref, v2) == "10");
223 #ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES
224     std::string& ref_to_string = boost::apply_visitor(visitor_ref, v1);
225     BOOST_TEST(ref_to_string == "1");
226 #endif
227     lex_streamer_void lex_streamer_void_visitor;
228     boost::apply_visitor(lex_streamer_void(), v1);
229     boost::apply_visitor(lex_streamer_void(), v2);
230 #ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES
231     boost::apply_visitor(lex_streamer_void_visitor)(v2);
232 #endif
233 
234     boost::ignore_unused(lex_streamer_visitor, visitor_ref, lex_streamer_void_visitor);
235 }
236 
237 
238 struct lex_combine {
239     template <class T1, class T2>
operator ()lex_combine240     std::string operator()(const T1& v1, const T2& v2) const {
241         return boost::lexical_cast<std::string>(v1) + "+" + boost::lexical_cast<std::string>(v2);
242     }
243 
244 
245     template <class T1, class T2, class T3>
operator ()lex_combine246     std::string operator()(const T1& v1, const T2& v2, const T3& v3) const {
247         return boost::lexical_cast<std::string>(v1) + "+"
248                 + boost::lexical_cast<std::string>(v2) + '+'
249                 + boost::lexical_cast<std::string>(v3);
250     }
251 };
252 
run2()253 void run2()
254 {
255     typedef boost::variant<int, std::string, double> variant_type;
256     variant_type v1(1), v2("10"), v3(100.0);
257     lex_combine lex_combine_visitor;
258 
259     BOOST_TEST(boost::apply_visitor(lex_combine(), v1, v2) == "1+10");
260     BOOST_TEST(boost::apply_visitor(lex_combine(), v2, v1) == "10+1");
261     BOOST_TEST_IF_HAS_VARIADIC(boost::apply_visitor(lex_combine_visitor)(v2, v1) == "10+1");
262 
263 
264     #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS
265         BOOST_TEST(
266             boost::apply_visitor(
267                 [](auto v1, auto v2) {
268                     return boost::lexical_cast<std::string>(v1) + "+"
269                         + boost::lexical_cast<std::string>(v2);
270                 }
271                 , v1
272                 , v2
273             ) == "1+10"
274         );
275         BOOST_TEST(
276             boost::apply_visitor(
277                 [](auto v1, auto v2) {
278                     return boost::lexical_cast<std::string>(v1) + "+"
279                         + boost::lexical_cast<std::string>(v2);
280                 }
281                 , v2
282                 , v1
283             ) == "10+1"
284         );
285 
286         boost::apply_visitor([](auto v1, auto v2) { std::cout << v1 << '+' << v2 << std::endl; }, v1, v2);
287         boost::apply_visitor([](auto v1, auto v2) { std::cout << v1 << '+' << v2 << std::endl; }, v2, v1);
288     #endif
289 
290 
291     lex_streamer2 visitor_ref;
292     BOOST_TEST(boost::apply_visitor(visitor_ref, v1, v2) == "1+10");
293     BOOST_TEST(boost::apply_visitor(visitor_ref, v2, v1) == "10+1");
294 #ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES
295     std::string& ref_to_string = boost::apply_visitor(visitor_ref)(v1, v2);
296     BOOST_TEST(ref_to_string == "1+10");
297 #endif
298 
299     boost::apply_visitor(lex_streamer_void(), v1, v2);
300     boost::apply_visitor(lex_streamer_void(), v2, v1);
301 
302     boost::ignore_unused(lex_combine_visitor, visitor_ref);
303 }
304 
305 #undef BOOST_TEST_IF_HAS_VARIADIC
306 
run3()307 void run3()
308 {
309 #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
310     typedef boost::variant<int, std::string, double> variant_type;
311     variant_type v1(1), v2("10"), v3(100);
312     lex_combine lex_combine_visitor;
313 
314     BOOST_TEST(boost::apply_visitor(lex_combine(), v1, v2, v3) == "1+10+100");
315     BOOST_TEST(boost::apply_visitor(lex_combine(), v2, v1, v3) == "10+1+100");
316     BOOST_TEST(boost::apply_visitor(lex_combine_visitor)(v2, v1, v3) == "10+1+100");
317 
318 
319     #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS
320         BOOST_TEST(
321             boost::apply_visitor(
322                 [](auto v1, auto v2, auto v3) {
323                     return boost::lexical_cast<std::string>(v1) + "+"
324                         + boost::lexical_cast<std::string>(v2) + "+"
325                         + boost::lexical_cast<std::string>(v3);
326                 }
327                 , v1
328                 , v2
329                 , v3
330             ) == "1+10+100"
331         );
332         BOOST_TEST(
333             boost::apply_visitor(
334                 [](auto v1, auto v2, auto v3) {
335                     return boost::lexical_cast<std::string>(v1) + "+"
336                         + boost::lexical_cast<std::string>(v2) + "+"
337                         + boost::lexical_cast<std::string>(v3);
338                 }
339                 , v3
340                 , v1
341                 , v3
342             ) == "100+1+100"
343         );
344 
345         boost::apply_visitor(
346             [](auto v1, auto v2, auto v3) { std::cout << v1 << '+' << v2 << '+' << v3 << std::endl; },
347             v1, v2, v3
348         );
349         boost::apply_visitor(
350             [](auto v1, auto v2, auto v3) { std::cout << v1 << '+' << v2 << '+' << v3 << std::endl; },
351             v2, v1, v3
352         );
353     #endif
354 
355 
356     lex_streamer2 visitor_ref;
357     BOOST_TEST(boost::apply_visitor(visitor_ref, v1, v2) == "1+10");
358     BOOST_TEST(boost::apply_visitor(visitor_ref)(v2, v1) == "10+1");
359     std::string& ref_to_string = boost::apply_visitor(visitor_ref, v1, v2);
360     BOOST_TEST(ref_to_string == "1+10");
361 
362     lex_streamer_void lex_streamer_void_visitor;
363     boost::apply_visitor(lex_streamer_void(), v1, v2, v1);
364     boost::apply_visitor(lex_streamer_void(), v2, v1, v1);
365     boost::apply_visitor(lex_streamer_void_visitor)(v2, v1, v1);
366 #endif // !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
367 }
368 #endif
369 
370 
main()371 int main()
372 {
373     run_explicit();
374     run();
375     run2();
376     run3();
377     test_has_result_type_triat();
378 
379     return boost::report_errors();
380 }
381