1 //-----------------------------------------------------------------------------
2 // boost-libs variant/test/variant_get_test.cpp source file
3 // See http://www.boost.org for updates, documentation, and revision history.
4 //-----------------------------------------------------------------------------
5 //
6 // Copyright (c) 2014-2019 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 #ifdef _MSC_VER
13 #pragma warning(disable: 4127) // conditional expression is constant
14 #pragma warning(disable: 4181) // qualifier applied to reference type; ignored
15 #endif
16 
17 #include "boost/variant/get.hpp"
18 #include "boost/variant/variant.hpp"
19 #include "boost/variant/polymorphic_get.hpp"
20 #include "boost/variant/recursive_wrapper.hpp"
21 #include "boost/core/lightweight_test.hpp"
22 
23 struct base {
24     int trash;
25 
basebase26     base() : trash(123) {}
basebase27     base(const base& b) : trash(b.trash) { int i = 100; (void)i; }
operator =base28     const base& operator=(const base& b) {
29         trash = b.trash;
30         int i = 100; (void)i;
31 
32         return *this;
33     }
34 
~basebase35     virtual ~base(){}
36 };
37 
38 struct derived1 : base{};
39 struct derived2 : base{};
40 
~vbasevbase41 struct vbase { short trash; virtual ~vbase(){} virtual int foo() const { return 0; }  };
foovderived142 struct vderived1 : virtual vbase{ virtual int foo() const { return 1; } };
foovderived243 struct vderived2 : virtual vbase{ virtual int foo() const { return 3; } };
foovderived344 struct vderived3 : vderived1, vderived2 { virtual int foo() const { return 3; } };
45 
46 typedef boost::variant<int, base, derived1, derived2, std::string> var_t;
47 typedef boost::variant<int, derived1, derived2, std::string> var_t_shortened;
48 typedef boost::variant<base, derived1, derived2> var_t_no_fallback;
49 typedef boost::variant<int&, base&, derived1&, derived2&, std::string&> var_ref_t;
50 typedef boost::variant<const int&, const base&, const derived1&, const derived2&, const std::string&> var_cref_t;
51 
52 struct recursive_structure;
53 typedef boost::variant<
54     int, base, derived1, derived2, std::string, boost::recursive_wrapper<recursive_structure>
55 > var_req_t;
56 struct recursive_structure { var_req_t var; };
57 
58 template <class TypeInVariant, class V, class TestType>
check_polymorphic_get_on_types_impl_single_type(V * v)59 inline void check_polymorphic_get_on_types_impl_single_type(V* v)
60 {
61     typedef typename boost::add_reference<TestType>::type ref_test_t;
62     typedef typename boost::add_reference<const TestType>::type cref_test_t;
63     const bool exact_same = !!boost::is_same<TypeInVariant, TestType>::value;
64     const bool ref_same = !!boost::is_same<TypeInVariant, ref_test_t>::value;
65 
66     if (exact_same || ref_same) {
67         BOOST_TEST(boost::polymorphic_get<TestType>(v));
68         BOOST_TEST(boost::polymorphic_get<const TestType>(v));
69         BOOST_TEST(boost::polymorphic_strict_get<TestType>(v));
70         BOOST_TEST(boost::polymorphic_strict_get<const TestType>(v));
71         BOOST_TEST(boost::polymorphic_relaxed_get<TestType>(v));
72         BOOST_TEST(boost::polymorphic_relaxed_get<const TestType>(v));
73 
74         BOOST_TEST(boost::polymorphic_get<cref_test_t>(v));
75         BOOST_TEST(boost::polymorphic_strict_get<cref_test_t>(v));
76         BOOST_TEST(boost::polymorphic_relaxed_get<cref_test_t>(v));
77 
78         if (ref_same) {
79             BOOST_TEST(boost::polymorphic_get<ref_test_t>(v));
80             BOOST_TEST(boost::polymorphic_get<cref_test_t>(v));
81             BOOST_TEST(boost::polymorphic_strict_get<ref_test_t>(v));
82             BOOST_TEST(boost::polymorphic_strict_get<cref_test_t>(v));
83             BOOST_TEST(boost::polymorphic_relaxed_get<ref_test_t>(v));
84             BOOST_TEST(boost::polymorphic_relaxed_get<cref_test_t>(v));
85         }
86     } else {
87         BOOST_TEST(!boost::polymorphic_get<TestType>(v));
88         BOOST_TEST(!boost::polymorphic_get<const TestType>(v));
89         BOOST_TEST(!boost::polymorphic_strict_get<TestType>(v));
90         BOOST_TEST(!boost::polymorphic_strict_get<const TestType>(v));
91         BOOST_TEST(!boost::polymorphic_relaxed_get<TestType>(v));
92         BOOST_TEST(!boost::polymorphic_relaxed_get<const TestType>(v));
93     }
94 }
95 
96 template <class T, class V, class TestType>
check_get_on_types_impl_single_type(V * v)97 inline void check_get_on_types_impl_single_type(V* v)
98 {
99     typedef typename boost::add_reference<TestType>::type ref_test_t;
100     typedef typename boost::add_reference<const TestType>::type cref_test_t;
101     const bool exact_same = !!boost::is_same<T, TestType>::value;
102     const bool ref_same = !!boost::is_same<T, ref_test_t>::value;
103 
104     if (exact_same || ref_same) {
105         BOOST_TEST(boost::get<TestType>(v));
106         BOOST_TEST(boost::get<const TestType>(v));
107         BOOST_TEST(boost::strict_get<TestType>(v));
108         BOOST_TEST(boost::strict_get<const TestType>(v));
109         BOOST_TEST(boost::relaxed_get<TestType>(v));
110         BOOST_TEST(boost::relaxed_get<const TestType>(v));
111 
112         BOOST_TEST(boost::get<cref_test_t>(v));
113         BOOST_TEST(boost::strict_get<cref_test_t>(v));
114         BOOST_TEST(boost::relaxed_get<cref_test_t>(v));
115 
116         if (ref_same) {
117             BOOST_TEST(boost::get<ref_test_t>(v));
118             BOOST_TEST(boost::get<cref_test_t>(v));
119             BOOST_TEST(boost::strict_get<ref_test_t>(v));
120             BOOST_TEST(boost::strict_get<cref_test_t>(v));
121             BOOST_TEST(boost::relaxed_get<ref_test_t>(v));
122             BOOST_TEST(boost::relaxed_get<cref_test_t>(v));
123         }
124     } else {
125         BOOST_TEST(!boost::get<TestType>(v));
126         BOOST_TEST(!boost::get<const TestType>(v));
127         BOOST_TEST(!boost::strict_get<TestType>(v));
128         BOOST_TEST(!boost::strict_get<const TestType>(v));
129         BOOST_TEST(!boost::relaxed_get<TestType>(v));
130         BOOST_TEST(!boost::relaxed_get<const TestType>(v));
131     }
132 }
133 
134 template <class T, class V>
check_get_on_types_impl(V * v)135 inline void check_get_on_types_impl(V* v)
136 {
137     check_get_on_types_impl_single_type<T, V, int>(v);
138     check_polymorphic_get_on_types_impl_single_type<T, V, int>(v);
139 
140     check_get_on_types_impl_single_type<T, V, base>(v);
141 
142     check_get_on_types_impl_single_type<T, V, derived1>(v);
143     check_polymorphic_get_on_types_impl_single_type<T, V, derived1>(v);
144 
145     check_get_on_types_impl_single_type<T, V, derived2>(v);
146     check_polymorphic_get_on_types_impl_single_type<T, V, derived2>(v);
147 
148     check_get_on_types_impl_single_type<T, V, std::string>(v);
149     check_polymorphic_get_on_types_impl_single_type<T, V, std::string>(v);
150 
151     // Never exist in here
152     BOOST_TEST(!boost::relaxed_get<short>(v));
153     BOOST_TEST(!boost::relaxed_get<const short>(v));
154     BOOST_TEST(!boost::relaxed_get<char>(v));
155     BOOST_TEST(!boost::relaxed_get<char*>(v));
156     BOOST_TEST(!boost::relaxed_get<bool>(v));
157     BOOST_TEST(!boost::relaxed_get<const bool>(v));
158 
159     BOOST_TEST(!boost::polymorphic_relaxed_get<short>(v));
160     BOOST_TEST(!boost::polymorphic_relaxed_get<const short>(v));
161     BOOST_TEST(!boost::polymorphic_relaxed_get<char>(v));
162     BOOST_TEST(!boost::polymorphic_relaxed_get<char*>(v));
163     BOOST_TEST(!boost::polymorphic_relaxed_get<bool>(v));
164     BOOST_TEST(!boost::polymorphic_relaxed_get<const bool>(v));
165 
166     boost::get<T>(*v);              // Must compile
167     boost::get<const T>(*v);        // Must compile
168     boost::strict_get<T>(*v);         // Must compile
169     boost::strict_get<const T>(*v);   // Must compile
170 
171     bool is_ref = boost::is_lvalue_reference<T>::value;
172     (void)is_ref;
173     if (!is_ref) {
174         boost::polymorphic_get<T>(*v);              // Must compile
175         boost::polymorphic_get<const T>(*v);        // Must compile
176         boost::polymorphic_strict_get<T>(*v);         // Must compile
177         boost::polymorphic_strict_get<const T>(*v);   // Must compile
178     }
179 }
180 
181 template <class T, class V>
check_get_on_types(V * v)182 inline void check_get_on_types(V* v)
183 {
184     check_get_on_types_impl<T, V>(v);
185     check_get_on_types_impl<T, const V>(v);
186 }
187 
get_test()188 inline void get_test()
189 {
190     var_t v;
191     check_get_on_types<int>(&v);
192 
193     var_t(base()).swap(v);
194     check_get_on_types<base>(&v);
195 
196     var_t(derived1()).swap(v);
197     check_get_on_types<derived1>(&v);
198 
199     var_t(derived2()).swap(v);
200     check_get_on_types<derived2>(&v);
201 
202     var_t(std::string("Hello")).swap(v);
203     check_get_on_types<std::string>(&v);
204 
205     var_t_shortened vs = derived2();
206     check_polymorphic_get_on_types_impl_single_type<derived2, var_t_shortened, int>(&vs);
207     check_polymorphic_get_on_types_impl_single_type<derived2, const var_t_shortened, int>(&vs);
208     // Checking that Base is really determinated
209     check_polymorphic_get_on_types_impl_single_type<base, var_t_shortened, base>(&vs);
210     check_polymorphic_get_on_types_impl_single_type<base, const var_t_shortened, base>(&vs);
211 
212     vs = derived1();
213     check_polymorphic_get_on_types_impl_single_type<derived2, var_t_shortened, int>(&vs);
214     check_polymorphic_get_on_types_impl_single_type<derived2, const var_t_shortened, int>(&vs);
215     // Checking that Base is really determinated
216     check_polymorphic_get_on_types_impl_single_type<base, var_t_shortened, base>(&vs);
217     check_polymorphic_get_on_types_impl_single_type<base, const var_t_shortened, base>(&vs);
218 }
219 
get_test_no_fallback()220 inline void get_test_no_fallback()
221 {
222     var_t_no_fallback v;
223     var_t_no_fallback(base()).swap(v);
224     check_polymorphic_get_on_types_impl_single_type<base, var_t_no_fallback, base>(&v);
225     check_polymorphic_get_on_types_impl_single_type<base, const var_t_no_fallback, base>(&v);
226     check_get_on_types_impl_single_type<base, var_t_no_fallback, base>(&v);
227     check_get_on_types_impl_single_type<base, const var_t_no_fallback, base>(&v);
228 
229     var_t_no_fallback(derived1()).swap(v);
230     check_polymorphic_get_on_types_impl_single_type<base, var_t_no_fallback, base>(&v);
231     check_polymorphic_get_on_types_impl_single_type<base, const var_t_no_fallback, base>(&v);
232     check_get_on_types_impl_single_type<derived1, var_t_no_fallback, derived1>(&v);
233     check_get_on_types_impl_single_type<derived1, const var_t_no_fallback, derived1>(&v);
234 
235     var_t_no_fallback(derived2()).swap(v);
236     check_polymorphic_get_on_types_impl_single_type<base, var_t_no_fallback, base>(&v);
237     check_polymorphic_get_on_types_impl_single_type<base, const var_t_no_fallback, base>(&v);
238     check_get_on_types_impl_single_type<derived2, var_t_no_fallback, derived2>(&v);
239     check_get_on_types_impl_single_type<derived2, const var_t_no_fallback, derived2>(&v);
240 }
241 
get_ref_test()242 inline void get_ref_test()
243 {
244     int i = 0;
245     var_ref_t v(i);
246     check_get_on_types<int>(&v);
247     check_get_on_types<int&>(&v);
248 
249     base b;
250     var_ref_t v1(b);
251     check_get_on_types<base>(&v1);
252     check_get_on_types<base&>(&v1);
253 
254     derived1 d1;
255     var_ref_t v2(d1);
256     check_get_on_types<derived1>(&v2);
257     check_get_on_types<derived1&>(&v2);
258 
259     derived2 d2;
260     var_ref_t v3(d2);
261     check_get_on_types<derived2>(&v3);
262     check_get_on_types<derived2&>(&v3);
263 
264     std::string s("Hello");
265     var_ref_t v4(s);
266     check_get_on_types<std::string>(&v4);
267     check_get_on_types<std::string&>(&v4);
268 }
269 
270 
get_cref_test()271 inline void get_cref_test()
272 {
273     int i = 0;
274     var_cref_t v(i);
275     BOOST_TEST(boost::get<const int>(&v));
276     BOOST_TEST(boost::get<const int&>(&v));
277     BOOST_TEST(!boost::get<const base>(&v));
278 
279     base b;
280     var_cref_t v1(b);
281     BOOST_TEST(boost::get<const base>(&v1));
282     BOOST_TEST(!boost::get<const derived1>(&v1));
283     BOOST_TEST(!boost::get<const int>(&v1));
284 
285     std::string s("Hello");
286     const var_cref_t v4 = s;
287     BOOST_TEST(boost::get<const std::string>(&v4));
288     BOOST_TEST(!boost::get<const int>(&v4));
289 }
290 
get_recursive_test()291 inline void get_recursive_test()
292 {
293     var_req_t v;
294     check_get_on_types<int>(&v);
295 
296     var_req_t(base()).swap(v);
297     check_get_on_types<base>(&v);
298 
299     var_req_t(derived1()).swap(v);
300     check_get_on_types<derived1>(&v);
301 
302     var_req_t(derived2()).swap(v);
303     check_get_on_types<derived2>(&v);
304 
305     var_req_t(std::string("Hello")).swap(v);
306     check_get_on_types<std::string>(&v);
307 
308     recursive_structure s = { v }; // copying "v"
309     v = s;
310     check_get_on_types<recursive_structure>(&v);
311 }
312 
313 template <class T>
check_that_does_not_exist_impl()314 inline void check_that_does_not_exist_impl()
315 {
316     using namespace boost::detail::variant;
317 
318     BOOST_TEST((holds_element<T, const int>::value));
319     BOOST_TEST((!holds_element<T, short>::value));
320     BOOST_TEST((!holds_element<T, short>::value));
321     BOOST_TEST((!holds_element<T, const short>::value));
322     BOOST_TEST((!holds_element<T, char*>::value));
323     BOOST_TEST((!holds_element<T, const char*>::value));
324     BOOST_TEST((!holds_element<T, char[5]>::value));
325     BOOST_TEST((!holds_element<T, const char[5]>::value));
326     BOOST_TEST((!holds_element<T, bool>::value));
327     BOOST_TEST((!holds_element<T, const bool>::value));
328 
329     BOOST_TEST((!holds_element<T, boost::recursive_wrapper<int> >::value));
330     BOOST_TEST((!holds_element<T, boost::recursive_wrapper<short> >::value));
331     BOOST_TEST((!holds_element<T, boost::detail::reference_content<short> >::value));
332 
333 
334     BOOST_TEST((holds_element_polymorphic<T, const int>::value));
335     BOOST_TEST((!holds_element_polymorphic<T, short>::value));
336     BOOST_TEST((!holds_element_polymorphic<T, short>::value));
337     BOOST_TEST((!holds_element_polymorphic<T, const short>::value));
338     BOOST_TEST((!holds_element_polymorphic<T, char*>::value));
339     BOOST_TEST((!holds_element_polymorphic<T, const char*>::value));
340     BOOST_TEST((!holds_element_polymorphic<T, char[5]>::value));
341     BOOST_TEST((!holds_element_polymorphic<T, const char[5]>::value));
342     BOOST_TEST((!holds_element_polymorphic<T, bool>::value));
343     BOOST_TEST((!holds_element_polymorphic<T, const bool>::value));
344 
345     BOOST_TEST((!holds_element_polymorphic<T, boost::recursive_wrapper<int> >::value));
346     BOOST_TEST((!holds_element_polymorphic<T, boost::recursive_wrapper<short> >::value));
347     BOOST_TEST((!holds_element_polymorphic<T, boost::detail::reference_content<short> >::value));
348 }
349 
check_that_does_not_exist()350 inline void check_that_does_not_exist()
351 {
352     using namespace boost::detail::variant;
353 
354     BOOST_TEST((holds_element<var_t, int>::value));
355     BOOST_TEST((holds_element<var_ref_t, int>::value));
356     BOOST_TEST((!holds_element<var_cref_t, int>::value));
357 
358     check_that_does_not_exist_impl<var_t>();
359     check_that_does_not_exist_impl<var_ref_t>();
360     check_that_does_not_exist_impl<var_cref_t>();
361     check_that_does_not_exist_impl<var_req_t>();
362 }
363 
364 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
365 class MoveonlyType {
366 public:
MoveonlyType()367     MoveonlyType() {}
~MoveonlyType()368     ~MoveonlyType() {}
369 
MoveonlyType(MoveonlyType &&)370     MoveonlyType(MoveonlyType&&) {}
operator =(MoveonlyType &&)371     void operator=(MoveonlyType&&) {}
372 
373 private:
374     MoveonlyType(const MoveonlyType&);
375     void operator=(const MoveonlyType&);
376 };
377 
foo1()378 const boost::variant<int, std::string> foo1() { return ""; }
foo2()379 boost::variant<int, std::string> foo2() { return ""; }
380 
get_rvref_test()381 inline void get_rvref_test()
382 {
383   boost::get<std::string>(foo1());
384   boost::get<std::string>(foo2());
385 
386   boost::variant<MoveonlyType, int> v;
387 
388   v = MoveonlyType();
389   boost::get<MoveonlyType>(boost::move(v));
390 
391   v = 3;
392 
393   v = MoveonlyType();
394   boost::get<MoveonlyType>(v);
395 
396   boost::relaxed_get<MoveonlyType&>(boost::variant<MoveonlyType, int>());
397 
398   v = MoveonlyType();
399   MoveonlyType moved_from_variant(boost::get<MoveonlyType>(boost::move(v)));
400 }
401 #endif  // BOOST_NO_CXX11_RVALUE_REFERENCES
402 
main()403 int main()
404 {
405     get_test();
406     get_test_no_fallback();
407     get_ref_test();
408     get_cref_test();
409     get_recursive_test();
410     check_that_does_not_exist();
411 
412 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
413     get_rvref_test();
414 #endif
415 
416     return boost::report_errors();
417 }
418