1
2 // Copyright 2017 Peter Dimov.
3 //
4 // Distributed under the Boost Software License, Version 1.0.
5 //
6 // See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt
8
9 #if defined(_MSC_VER)
10 # pragma warning( disable: 4702 ) // unreachable code
11 #endif
12
13 #include <boost/variant2/variant.hpp>
14 #include <boost/core/lightweight_test.hpp>
15 #include <type_traits>
16 #include <utility>
17 #include <string>
18 #include <stdexcept>
19
20 using namespace boost::variant2;
21 namespace v2d = boost::variant2::detail;
22
23 #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
24
25 //
26
27 enum E1 { e1 };
28 enum E1x { e1x };
29
30 struct X1
31 {
32 X1() = default;
33
X1X134 X1( E1 ) noexcept {}
X1X135 X1( E1x ) { throw std::runtime_error( "X1(E1x)" ); }
36 };
37
38 STATIC_ASSERT( std::is_nothrow_default_constructible<X1>::value );
39 STATIC_ASSERT( std::is_nothrow_copy_constructible<X1>::value );
40 STATIC_ASSERT( std::is_nothrow_move_constructible<X1>::value );
41 STATIC_ASSERT( std::is_trivially_destructible<X1>::value );
42 STATIC_ASSERT( v2d::is_trivially_move_assignable<X1>::value );
43 STATIC_ASSERT( std::is_nothrow_constructible<X1, E1>::value );
44 STATIC_ASSERT( !std::is_nothrow_constructible<X1, E1x>::value );
45
46 enum E2 { e2 };
47 enum E2x { e2x };
48
49 struct X2
50 {
51 X2();
52 ~X2();
53
X2X254 X2( E2 ) noexcept {}
X2X255 X2( E2x ) { throw std::runtime_error( "X2(E2x)" ); }
56 };
57
X2()58 X2::X2() {}
~X2()59 X2::~X2() {}
60
61 STATIC_ASSERT( !std::is_nothrow_default_constructible<X2>::value );
62 STATIC_ASSERT( std::is_nothrow_copy_constructible<X2>::value );
63 STATIC_ASSERT( std::is_nothrow_move_constructible<X2>::value );
64 STATIC_ASSERT( !std::is_trivially_destructible<X2>::value );
65 STATIC_ASSERT( std::is_nothrow_constructible<X2, E2>::value );
66 STATIC_ASSERT( !std::is_nothrow_constructible<X2, E2x>::value );
67
68 enum E3 { e3 };
69 enum E3x { e3x };
70
71 struct X3
72 {
73 X3();
74
X3X375 X3( X3 const& ) {}
X3X376 X3( X3&& ) {}
77
X3X378 X3( E3 ) noexcept {}
X3X379 X3( E3x ) { throw std::runtime_error( "X3(E3x)" ); }
80
81 X3& operator=( X3 const& ) = default;
82 X3& operator=( X3&& ) = default;
83 };
84
X3()85 X3::X3() {}
86
87 STATIC_ASSERT( !std::is_nothrow_default_constructible<X3>::value );
88 STATIC_ASSERT( !std::is_nothrow_copy_constructible<X3>::value );
89 STATIC_ASSERT( !std::is_nothrow_move_constructible<X3>::value );
90 STATIC_ASSERT( std::is_trivially_destructible<X3>::value );
91 //STATIC_ASSERT( v2d::is_trivially_move_assignable<X3>::value );
92 STATIC_ASSERT( std::is_nothrow_constructible<X3, E3>::value );
93 STATIC_ASSERT( !std::is_nothrow_constructible<X3, E3x>::value );
94
95 //
96
97 STATIC_ASSERT( std::is_nothrow_default_constructible<monostate>::value );
98 STATIC_ASSERT( std::is_nothrow_copy_constructible<monostate>::value );
99 STATIC_ASSERT( std::is_nothrow_move_constructible<monostate>::value );
100 STATIC_ASSERT( std::is_trivially_destructible<monostate>::value );
101
102 //
103
main()104 int main()
105 {
106 {
107 variant<X2, X1> v;
108
109 BOOST_TEST_EQ( v.index(), 0 );
110
111 try
112 {
113 v = e1x;
114 BOOST_ERROR( "`v = e1x;` failed to throw" );
115 }
116 catch( std::exception const& )
117 {
118 // strong guarantee
119 BOOST_TEST_EQ( v.index(), 0 );
120 }
121 }
122
123 {
124 variant<X1, X2> v( e2 );
125
126 BOOST_TEST_EQ( v.index(), 1 );
127
128 try
129 {
130 v = e1x;
131 BOOST_ERROR( "`v = e1x;` failed to throw" );
132 }
133 catch( std::exception const& )
134 {
135 // strong guarantee
136 BOOST_TEST_EQ( v.index(), 1 );
137 }
138 }
139
140 {
141 variant<X2, X1, monostate> v;
142
143 BOOST_TEST_EQ( v.index(), 0 );
144
145 try
146 {
147 v = e1x;
148 BOOST_ERROR( "`v = e1x;` failed to throw" );
149 }
150 catch( std::exception const& )
151 {
152 // strong guarantee
153 BOOST_TEST_EQ( v.index(), 0 );
154 }
155 }
156
157 {
158 variant<X1, X2, monostate> v( e2 );
159
160 BOOST_TEST_EQ( v.index(), 1 );
161
162 try
163 {
164 v = e1x;
165 BOOST_ERROR( "`v = e1x;` failed to throw" );
166 }
167 catch( std::exception const& )
168 {
169 // strong guarantee
170 BOOST_TEST_EQ( v.index(), 1 );
171 }
172 }
173
174 {
175 variant<X2, X3, X1> v;
176
177 BOOST_TEST_EQ( v.index(), 0 );
178
179 try
180 {
181 v = e3x;
182 BOOST_ERROR( "`v = e3x;` failed to throw" );
183 }
184 catch( std::exception const& )
185 {
186 // strong guarantee
187 BOOST_TEST_EQ( v.index(), 0 );
188 }
189 }
190
191 {
192 variant<X2, X3, X1, monostate> v;
193
194 BOOST_TEST_EQ( v.index(), 0 );
195
196 try
197 {
198 v = e3x;
199 BOOST_ERROR( "`v = e3x;` failed to throw" );
200 }
201 catch( std::exception const& )
202 {
203 // strong guarantee
204 BOOST_TEST_EQ( v.index(), 0 );
205 }
206 }
207
208 {
209 variant<X2, X3> v;
210
211 BOOST_TEST_EQ( v.index(), 0 );
212
213 try
214 {
215 v = e3x;
216 BOOST_ERROR( "`v = e3x;` failed to throw" );
217 }
218 catch( std::exception const& )
219 {
220 // double buffered, no change
221 BOOST_TEST_EQ( v.index(), 0 );
222 }
223 }
224
225 {
226 variant<X3, X1> v;
227
228 BOOST_TEST_EQ( v.index(), 0 );
229
230 try
231 {
232 v = e1x;
233 BOOST_ERROR( "`v = e1x;` failed to throw" );
234 }
235 catch( std::exception const& )
236 {
237 // strong guarantee
238 BOOST_TEST_EQ( v.index(), 0 );
239 }
240 }
241
242 {
243 variant<X3, X1, monostate> v;
244
245 BOOST_TEST_EQ( v.index(), 0 );
246
247 try
248 {
249 v = e1x;
250 BOOST_ERROR( "`v = e1x;` failed to throw" );
251 }
252 catch( std::exception const& )
253 {
254 // strong guarantee
255 BOOST_TEST_EQ( v.index(), 0 );
256 }
257 }
258
259 return boost::report_errors();
260 }
261