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