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) 2016-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 
13 // This test suite was created to cover issues reported in:
14 //      https://svn.boost.org/trac/boost/ticket/5871
15 //      https://svn.boost.org/trac/boost/ticket/11602
16 
17 #include "boost/variant/variant.hpp"
18 #include "boost/variant/recursive_variant.hpp"
19 #include "boost/core/lightweight_test.hpp"
20 
21 #include <string>
22 #include <list>
23 
24 struct A{};
25 struct B{};
26 struct C{};
27 struct D{};
28 
29 
foo(const boost::variant<A,B> &)30 bool foo(const boost::variant<A, B>& ) {
31     return false;
32 }
33 
foo(const boost::variant<C,D> &)34 bool foo(const boost::variant<C, D>& ) {
35     return true;
36 }
37 
test_overload_selection_variant_constructor()38 void test_overload_selection_variant_constructor() {
39     D d;
40     BOOST_TEST(foo(d));
41 
42     boost::variant<B, A> v;
43     BOOST_TEST(!foo(v));
44 }
45 
46 // Pre msvc-14.0 could not dustinguish between multiple assignment operators:
47 //      warning C4522: 'assignment_tester' : multiple assignment operators specified
48 //      error C2666: variant::operator =' : 3 overloads have similar conversions
49 // Old versions of GCC have same issue:
50 //      error: variant::operator=(const T&) cannot be overloaded
51 #if (defined(__GNUC__) && (__GNUC__ < 4)) || (defined(_MSC_VER) && _MSC_VER < 1900)
52 
test_overload_selection_variant_assignment()53 void test_overload_selection_variant_assignment() {
54     BOOST_TEST(true);
55 }
56 
57 #else
58 
59 struct assignment_tester: boost::variant<C, D>, boost::variant<B, A> {
60     using boost::variant<B, A>::operator=;
61     using boost::variant<C, D>::operator=;
62 };
63 
test_overload_selection_variant_assignment()64 void test_overload_selection_variant_assignment() {
65     A a;
66     assignment_tester tester;
67     tester = a;
68     const int which0 = static_cast< boost::variant<B, A>& >(tester).which();
69     BOOST_TEST(which0 == 1);
70 
71     boost::variant<A, B> b;
72     b = B();
73     tester = b;
74     const int which1 = static_cast< boost::variant<B, A>& >(tester).which();
75     BOOST_TEST(which1 == 0);
76 }
77 
78 #endif
79 
80 typedef boost::variant<int> my_variant;
81 
82 struct convertible {
operator my_variantconvertible83     operator my_variant() const {
84         return my_variant();
85     }
86 };
87 
test_implicit_conversion_operator()88 void test_implicit_conversion_operator() {
89     // https://svn.boost.org/trac/boost/ticket/8555
90     my_variant y = convertible();
91     BOOST_TEST(y.which() == 0);
92 }
93 
94 struct X: boost::variant< int > {};
95 class V1: public boost::variant<float,double> {};
96 
97 struct AB: boost::variant<A, B> {};
98 
test_derived_from_variant_construction()99 void test_derived_from_variant_construction() {
100     // https://svn.boost.org/trac/boost/ticket/7120
101     X x;
102     boost::variant<X> y(x);
103     BOOST_TEST(y.which() == 0);
104 
105     // https://svn.boost.org/trac/boost/ticket/10278
106     boost::variant<V1, std::string> v2 = V1();
107     BOOST_TEST(v2.which() == 0);
108 
109     // https://svn.boost.org/trac/boost/ticket/12155
110     AB ab;
111     boost::variant<AB, C> ab_c(ab);
112     BOOST_TEST(ab_c.which() == 0);
113 
114     boost::variant<A, B> a_b(ab);
115     BOOST_TEST(a_b.which() == 0);
116 
117     boost::variant<B, C, A> b_c_a1(static_cast<boost::variant<A, B>& >(ab));
118     BOOST_TEST(b_c_a1.which() == 2);
119 
120 
121 //  Following conversion seems harmful as it may lead to slicing:
122 //  boost::variant<B, C, A> b_c_a(ab);
123 //  BOOST_TEST(b_c_a.which() == 2);
124 }
125 
test_derived_from_variant_assignment()126 void test_derived_from_variant_assignment() {
127     // https://svn.boost.org/trac/boost/ticket/7120
128     X x;
129     boost::variant<X> y;
130     y = x;
131     BOOST_TEST(y.which() == 0);
132 
133     // https://svn.boost.org/trac/boost/ticket/10278
134     boost::variant<V1, std::string> v2;
135     v2 = V1();
136     BOOST_TEST(v2.which() == 0);
137 
138     // https://svn.boost.org/trac/boost/ticket/12155
139     AB ab;
140     boost::variant<AB, C> ab_c;
141     ab_c = ab;
142     BOOST_TEST(ab_c.which() == 0);
143 
144     boost::variant<A, B> a_b;
145     a_b = ab;
146     BOOST_TEST(a_b.which() == 0);
147 
148     boost::variant<B, C, A> b_c_a1;
149     b_c_a1 = static_cast<boost::variant<A, B>& >(ab);
150     BOOST_TEST(b_c_a1.which() == 2);
151 
152 
153 //  Following conversion seems harmful as it may lead to slicing:
154 //  boost::variant<B, C, A> b_c_a;
155 //  b_c_a = ab;
156 //  BOOST_TEST(b_c_a.which() == 2);
157 }
158 
159 
160 // http://thread.gmane.org/gmane.comp.lib.boost.devel/267757
161 struct info {
162     struct nil_ {};
163 
164     typedef
165         boost::variant<
166             nil_
167           , std::string
168           , boost::recursive_wrapper<info>
169           , boost::recursive_wrapper<std::pair<info, info> >
170           , boost::recursive_wrapper<std::list<info> >
171         >
172     value_type;
173     value_type v;
174 
test_on_incomplete_typesinfo175     inline void test_on_incomplete_types() {
176         info i0;
177         i0.v = "Hello";
178         BOOST_TEST(i0.v.which() == 1);
179 
180         info::value_type v0 = "Hello";
181         BOOST_TEST(v0.which() == 1);
182 
183         info::value_type v1("Hello");
184         BOOST_TEST(v1.which() == 1);
185 
186         info::value_type v2 = i0;
187         BOOST_TEST(v2.which() == 2);
188 
189         info::value_type v3(i0);
190         BOOST_TEST(v3.which() == 2);
191 
192         v0 = v3;
193         BOOST_TEST(v0.which() == 2);
194 
195         v3 = v1;
196         BOOST_TEST(v3.which() == 1);
197 
198         v3 = nil_();
199         BOOST_TEST(v3.which() == 0);
200     }
201 };
202 
203 
204 
main()205 int main()
206 {
207     test_overload_selection_variant_constructor();
208     test_overload_selection_variant_assignment();
209     test_implicit_conversion_operator();
210     test_derived_from_variant_construction();
211     test_derived_from_variant_assignment();
212     info().test_on_incomplete_types();
213 
214     return boost::report_errors();
215 }
216