• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2017 Levon Tarakchyan
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
7 #include "boost/config.hpp"
8 
9 #include "boost/core/lightweight_test.hpp"
10 #include "boost/variant.hpp"
11 #include "boost/variant/apply_visitor.hpp"
12 #include "boost/variant/multivisitors.hpp"
13 #include "boost/lexical_cast.hpp"
14 
15 #define lcs(val) boost::lexical_cast<std::string>(val)
16 
17 struct construction_logger
18 {
19     int val_;
20 
construction_loggerconstruction_logger21     construction_logger(int val) : val_(val)
22     {
23         std::cout << val_ << " constructed\n";
24     }
25 
construction_loggerconstruction_logger26     construction_logger(const construction_logger& cl) :
27         val_(cl.val_)
28     {
29         std::cout << val_ << " copy constructed\n";
30     }
31 
32 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
construction_loggerconstruction_logger33     construction_logger(construction_logger&& cl) :
34         val_(cl.val_)
35     {
36         std::cout << val_ << " move constructed\n";
37     }
38 #endif
39 
operator <<(std::ostream & os,const construction_logger & cl)40     friend std::ostream& operator << (std::ostream& os, const construction_logger& cl)
41     {
42         return os << cl.val_;
43     }
44 
operator <<(std::istream & is,construction_logger & cl)45     friend std::istream& operator << (std::istream& is, construction_logger& cl)
46     {
47         return is >> cl.val_;
48     }
49 };
50 
51 struct lex_streamer_explicit : boost::static_visitor<std::string>
52 {
53     template <class T>
operator ()lex_streamer_explicit54     std::string operator()(const T& val) const
55     {
56         return lcs(val);
57     }
58 
59     template <class T, class V>
operator ()lex_streamer_explicit60     std::string operator()(const T& val, const V& val2) const
61     {
62         return lcs(val) + '+' + lcs(val2);
63     }
64 
65     template <class T, class V, class P, class S>
operator ()lex_streamer_explicit66     std::string operator()(const T& val, const V& val2, const P& val3, const S& val4) const
67     {
68         return lcs(val) + '+' + lcs(val2) + '+' + lcs(val3) + '+' + lcs(val4);
69     }
70 };
71 
72 struct lvalue_rvalue_detector : boost::static_visitor<std::string>
73 {
74 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
75     template <class T>
operator ()lvalue_rvalue_detector76     std::string operator()(T&&) const
77     {
78         return std::is_lvalue_reference<T>::value ? "lvalue reference"
79                                                   : "rvalue reference";
80     }
81 
82     template <class T, class V>
operator ()lvalue_rvalue_detector83     std::string operator()(T&& t, V&& v) const
84     {
85         return operator()(std::forward<T>(t)) + ", " + operator()(std::forward<V>(v));
86     }
87 
88     template <class T, class V, class P>
operator ()lvalue_rvalue_detector89     std::string operator()(T&& t, V&& v, P&& p) const
90     {
91         return operator()(std::forward<T>(t), std::forward<V>(v)) + ", " + operator()(std::forward<P>(p));
92     }
93 
94     template <class T, class V, class P, class S>
operator ()lvalue_rvalue_detector95     std::string operator()(T&& t, V&& v, P&& p, S&& s) const
96     {
97         return operator()(std::forward<T>(t), std::forward<V>(v), std::forward<P>(p)) + ", " + operator()(std::forward<S>(s));
98     }
99 #else
100     template <class T>
101     std::string operator()(T&) const
102     {
103         return "lvalue reference";
104     }
105 
106     template <class T, class V>
107     std::string operator()(T&, V&) const
108     {
109         return "lvalue reference, lvalue reference";
110     }
111 
112     template <class T, class V, class P>
113     std::string operator()(T&, V&, P&) const
114     {
115         return "lvalue reference, lvalue reference, lvalue reference";
116     }
117 
118     template <class T, class V, class P, class S>
119     std::string operator()(T&, V&, P&, S&) const
120     {
121         return "lvalue reference, lvalue reference, lvalue reference, lvalue reference";
122     }
123 #endif
124 };
125 
126 typedef boost::variant<construction_logger, std::string> variant_type;
127 
test_const_ref_parameter(const variant_type & test_var)128 void test_const_ref_parameter(const variant_type& test_var)
129 {
130     std::cout << "Testing const lvalue reference visitable\n";
131 
132     BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), test_var) == "lvalue reference");
133 }
134 
test_const_ref_parameter2(const variant_type & test_var,const variant_type & test_var2)135 void test_const_ref_parameter2(const variant_type& test_var, const variant_type& test_var2)
136 {
137     std::cout << "Testing const lvalue reference visitable\n";
138 
139     BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), test_var, test_var2) == "lvalue reference, lvalue reference");
140 }
141 
test_const_ref_parameter4(const variant_type & test_var,const variant_type & test_var2,const variant_type & test_var3,const variant_type & test_var4)142 void test_const_ref_parameter4(const variant_type& test_var, const variant_type& test_var2, const variant_type& test_var3, const variant_type& test_var4)
143 {
144     std::cout << "Testing const lvalue reference visitable with multivisitor\n";
145 
146     BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), test_var, test_var2, test_var3, test_var4)
147             == "lvalue reference, lvalue reference, lvalue reference, lvalue reference");
148 }
149 
150 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_REF_QUALIFIERS)
151 
test_rvalue_parameter(variant_type && test_var)152 void test_rvalue_parameter(variant_type&& test_var)
153 {
154     std::cout << "Testing rvalue visitable\n";
155 
156     const auto expected_val = lcs(test_var);
157     BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), std::move(test_var)) == "rvalue reference");
158 }
159 
test_rvalue_parameter2(variant_type && test_var,variant_type && test_var2)160 void test_rvalue_parameter2(variant_type&& test_var, variant_type&& test_var2)
161 {
162     std::cout << "Testing rvalue visitable\n";
163 
164     BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), std::move(test_var), std::move(test_var2)) == "rvalue reference, rvalue reference");
165 }
166 
test_rvalue_parameter4(variant_type && test_var,variant_type && test_var2,variant_type && test_var3,variant_type && test_var4)167 void test_rvalue_parameter4(variant_type&& test_var, variant_type&& test_var2, variant_type&& test_var3, variant_type&& test_var4)
168 {
169 #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
170     std::cout << "Testing rvalue visitable with multivisitor\n";
171 
172     auto result = boost::apply_visitor(lvalue_rvalue_detector(), std::move(test_var), std::move(test_var2), std::move(test_var3), std::move(test_var4));
173     std::cout << "result: " << result << std::endl;
174     BOOST_TEST(result == "rvalue reference, rvalue reference, rvalue reference, rvalue reference");
175 #else
176     (void)test_var;
177     (void)test_var2;
178     (void)test_var3;
179     (void)test_var4;
180 #endif
181 }
182 
183 #endif
184 
185 #ifndef BOOST_NO_CXX14_DECLTYPE_AUTO
186 
187 #define FORWARD(x) std::forward<decltype(x)>(x)
188 
test_cpp14_visitor(const variant_type & test_var)189 void test_cpp14_visitor(const variant_type& test_var)
190 {
191     std::cout << "Testing const lvalue visitable for c++14\n";
192 
193     BOOST_TEST(boost::apply_visitor([](auto&& v) { return lvalue_rvalue_detector()(FORWARD(v)); }, test_var) == "lvalue reference");
194 }
195 
test_cpp14_mutable_visitor(const variant_type & test_var)196 void test_cpp14_mutable_visitor(const variant_type& test_var)
197 {
198     std::cout << "Testing const lvalue visitable for c++14 with inline mutable lambda\n";
199 
200     BOOST_TEST(boost::apply_visitor([](auto&& v) mutable -> auto { return lvalue_rvalue_detector()(FORWARD(v)); }, test_var) == "lvalue reference");
201 }
202 
test_cpp14_visitor(const variant_type & test_var,const variant_type & test_var2)203 void test_cpp14_visitor(const variant_type& test_var, const variant_type& test_var2)
204 {
205     std::cout << "Testing const lvalue visitable for c++14\n";
206 
207     BOOST_TEST(boost::apply_visitor([](auto&& v, auto&& vv) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(vv)); }, test_var, test_var2)
208             == "lvalue reference, lvalue reference");
209 }
210 
test_cpp14_visitor(const variant_type & test_var,const variant_type & test_var2,const variant_type & test_var3)211 void test_cpp14_visitor(const variant_type& test_var, const variant_type& test_var2, const variant_type& test_var3)
212 {
213 #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
214     std::cout << "Testing const lvalue visitable for c++14\n";
215 
216     auto result = boost::apply_visitor([](auto&& v, auto&& t, auto&& p) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t), FORWARD(p)); },
217                 test_var, test_var2, test_var3);
218     std::cout << "result: " << result << std::endl;
219     BOOST_TEST(result == "lvalue reference, lvalue reference, lvalue reference");
220 #else
221     (void)test_var;
222     (void)test_var2;
223     (void)test_var3;
224 #endif
225 }
226 
test_cpp14_visitor(variant_type & test_var)227 void test_cpp14_visitor(variant_type& test_var)
228 {
229     std::cout << "Testing lvalue visitable for c++14\n";
230 
231     BOOST_TEST(boost::apply_visitor([](auto& v) { return lvalue_rvalue_detector()(v); }, test_var) == "lvalue reference");
232 }
233 
test_cpp14_mutable_visitor(variant_type & test_var)234 void test_cpp14_mutable_visitor(variant_type& test_var)
235 {
236     std::cout << "Testing lvalue visitable for c++14 with inline mutable lambda\n";
237 
238     BOOST_TEST(boost::apply_visitor([](auto& v) mutable -> auto { return lvalue_rvalue_detector()(v); }, test_var) == "lvalue reference");
239 }
240 
test_cpp14_visitor(variant_type & test_var,variant_type & test_var2)241 void test_cpp14_visitor(variant_type& test_var, variant_type& test_var2)
242 {
243     std::cout << "Testing lvalue visitable for c++14\n";
244 
245     BOOST_TEST(boost::apply_visitor([](auto& v, auto& vv) { return lvalue_rvalue_detector()(v, vv); }, test_var, test_var2)
246             == "lvalue reference, lvalue reference");
247 }
248 
test_cpp14_visitor(variant_type & test_var,variant_type & test_var2,variant_type & test_var3)249 void test_cpp14_visitor(variant_type& test_var, variant_type& test_var2, variant_type& test_var3)
250 {
251 #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
252     std::cout << "Testing lvalue visitable for c++14\n";
253 
254     auto result = boost::apply_visitor([](auto& v, auto& t, auto& p) { return lvalue_rvalue_detector()(v, t, p); },
255                 test_var, test_var2, test_var3);
256     std::cout << "result: " << result << std::endl;
257     BOOST_TEST(result == "lvalue reference, lvalue reference, lvalue reference");
258 #else
259     (void)test_var;
260     (void)test_var2;
261     (void)test_var3;
262 #endif
263 }
264 
test_cpp14_visitor(variant_type && test_var)265 void test_cpp14_visitor(variant_type&& test_var)
266 {
267     std::cout << "Testing rvalue visitable for c++14\n";
268 
269     BOOST_TEST(boost::apply_visitor([](auto&& v) { return lvalue_rvalue_detector()(FORWARD(v)); }, std::move(test_var)) == "rvalue reference");
270 }
271 
test_cpp14_visitor(variant_type && test_var,variant_type && test_var2)272 void test_cpp14_visitor(variant_type&& test_var, variant_type&& test_var2)
273 {
274     std::cout << "Testing rvalue visitable for c++14\n";
275 
276     BOOST_TEST(boost::apply_visitor([](auto&& v, auto&& vv) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(vv)); }, std::move(test_var), std::move(test_var2))
277             == "rvalue reference, rvalue reference");
278 }
279 
test_cpp14_visitor(variant_type && test_var,variant_type && test_var2,variant_type && test_var3)280 void test_cpp14_visitor(variant_type&& test_var, variant_type&& test_var2, variant_type&& test_var3)
281 {
282 #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
283     std::cout << "Testing rvalue visitable for c++14\n";
284 
285     auto result = boost::apply_visitor([](auto&& v, auto&& t, auto&& p) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t), FORWARD(p)); },
286                 std::move(test_var), std::move(test_var2), std::move(test_var3));
287     std::cout << "result: " << result << std::endl;
288     BOOST_TEST(result == "rvalue reference, rvalue reference, rvalue reference");
289 #else
290     (void)test_var;
291     (void)test_var2;
292     (void)test_var3;
293 #endif
294 }
295 
296 #endif
297 
run_const_lvalue_ref_tests()298 void run_const_lvalue_ref_tests()
299 {
300     const variant_type v1(1), v2(2), v3(3), v4(4);
301     test_const_ref_parameter(v1);
302     test_const_ref_parameter2(v1, v2);
303     test_const_ref_parameter4(v1, v2, v3, v4);
304 }
305 
run_rvalue_ref_tests()306 void run_rvalue_ref_tests()
307 {
308 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_REF_QUALIFIERS)
309     variant_type v1(10), v2(20), v3(30);
310     test_rvalue_parameter(boost::move(v1));
311     test_rvalue_parameter2(boost::move(v2), boost::move(v3));
312 
313     variant_type vv1(100), vv2(200), vv3(300), vv4(400);
314     test_rvalue_parameter4(boost::move(vv1), boost::move(vv2), boost::move(vv3), boost::move(vv4));
315 #endif
316 }
317 
run_mixed_tests()318 void run_mixed_tests()
319 {
320     variant_type v1(1), v2(2);
321 
322 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
323 #ifndef BOOST_NO_CXX11_REF_QUALIFIERS
324     std::cout << "Testing lvalue + rvalue visitable\n";
325     BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), v1, variant_type(10)) == "lvalue reference, rvalue reference");
326 
327     std::cout << "Testing rvalue + lvalue visitable\n";
328     BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), variant_type(10), v1) == "rvalue reference, lvalue reference");
329 
330 #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
331     std::cout << "Testing rvalue + lvalue + rvalue visitable\n";
332     BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), variant_type(10), v1, variant_type(20)) == "rvalue reference, lvalue reference, rvalue reference");
333 
334     std::cout << "Testing lvalue + rvalue + lvalue + rvalue visitable\n";
335     BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), v1, variant_type(10), v2, variant_type(20)) == "lvalue reference, rvalue reference, lvalue reference, rvalue reference");
336 #endif
337 
338 #endif // #ifndef BOOST_NO_CXX11_REF_QUALIFIERS
339 
340 #else // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
341     std::cout << "Testing lvalue + rvalue visitable\n";
342     BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), v1, v1) == "lvalue reference, lvalue reference");
343 
344     std::cout << "Testing rvalue + lvalue visitable\n";
345     BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), static_cast<const variant_type&>(variant_type(10)), v1) == "lvalue reference, lvalue reference");
346 
347 #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
348     std::cout << "Testing rvalue + lvalue + rvalue visitable\n";
349     BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), static_cast<const variant_type&>(variant_type(10)), v1, static_cast<const variant_type&>(variant_type(20))) == "lvalue reference, lvalue reference, lvalue reference");
350 
351     std::cout << "Testing lvalue + rvalue + lvalue + rvalue visitable\n";
352     BOOST_TEST(boost::apply_visitor(lvalue_rvalue_detector(), v1, static_cast<const variant_type&>(variant_type(10)), v2, static_cast<const variant_type&>(variant_type(20))) == "lvalue reference, lvalue reference, lvalue reference, lvalue reference");
353 #endif
354 #endif
355 }
356 
run_cpp14_mixed_tests()357 void run_cpp14_mixed_tests()
358 {
359 #ifndef BOOST_NO_CXX14_DECLTYPE_AUTO
360     variant_type v1(1), v2(2);
361 
362     std::cout << "Testing lvalue + rvalue visitable\n";
363     BOOST_TEST(boost::apply_visitor([](auto&& v, auto&& t) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t)); },
364                 v1, variant_type(10)) == "lvalue reference, rvalue reference");
365 
366     std::cout << "Testing rvalue + lvalue visitable\n";
367     BOOST_TEST(boost::apply_visitor([](auto&& v, auto&& t) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t)); },
368                 variant_type(10), v1) == "rvalue reference, lvalue reference");
369 
370 #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE)
371     std::cout << "Testing rvalue + lvalue + lvalue visitable\n";
372     BOOST_TEST(boost::apply_visitor([](auto&& v, auto&& t, auto&& p) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t), FORWARD(p)); },
373                 variant_type(10), v1, v2) == "rvalue reference, lvalue reference, lvalue reference");
374 
375     std::cout << "Testing lvalue + rvalue + lvalue visitable\n";
376     BOOST_TEST(boost::apply_visitor([](auto&& v, auto&& t, auto&& p) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t), FORWARD(p)); },
377                 v1, variant_type(10), v2) == "lvalue reference, rvalue reference, lvalue reference");
378 #endif
379 #endif
380 }
381 
run_cpp14_tests()382 void run_cpp14_tests()
383 {
384 #ifndef BOOST_NO_CXX14_DECLTYPE_AUTO
385     variant_type const c1(10), c2(20), c3(30);
386     variant_type v1(10), v2(20), v3(30);
387 
388     test_cpp14_visitor(c1);
389     test_cpp14_mutable_visitor(c1);
390     test_cpp14_visitor(c2, c3);
391     test_cpp14_visitor(c1, c2, c3);
392 
393     test_cpp14_visitor(v1);
394     test_cpp14_mutable_visitor(v1);
395     test_cpp14_visitor(v2, v3);
396     test_cpp14_visitor(v1, v2, v3);
397 
398     test_cpp14_visitor(boost::move(v1));
399     test_cpp14_visitor(boost::move(v2), boost::move(v3));
400 
401     variant_type vv1(100), vv2(200), vv3(300);
402     test_cpp14_visitor(boost::move(vv1), boost::move(vv2), boost::move(vv3));
403 #endif
404 }
405 
406 
407 
main()408 int main()
409 {
410     run_const_lvalue_ref_tests();
411     run_rvalue_ref_tests();
412     run_mixed_tests();
413     run_cpp14_mixed_tests();
414     run_cpp14_tests();
415 
416     return boost::report_errors();
417 }
418