1 //-----------------------------------------------------------------------------
2 // boost-libs variant/test/rvalue_test.cpp source file
3 // See http://www.boost.org for updates, documentation, and revision history.
4 //-----------------------------------------------------------------------------
6 // Copyright (c) 2012-2019 Antony Polukhin
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)
12 #include "boost/config.hpp"
14 #include "boost/core/lightweight_test.hpp"
15 #include "boost/variant.hpp"
16 #include "boost/type_traits/is_nothrow_move_assignable.hpp"
17 #include "boost/mpl/bool.hpp"
19 #include <boost/blank.hpp>
20 #include <boost/swap.hpp>
22 namespace swap_ambiguouty_test_ns
{
26 void swap_ambiguouty_test() {
27 // If boost::blank is not used, then it compiles.
28 typedef boost::variant
<boost::blank
, A
, B
> Variant
;
32 } // namespace swap_ambiguouty_test_ns
34 // Most part of tests from this file require rvalue references support
36 class move_copy_conting_class
{
38 static unsigned int moves_count
;
39 static unsigned int copy_count
;
41 move_copy_conting_class(){}
42 move_copy_conting_class(BOOST_RV_REF(move_copy_conting_class
) ) {
46 move_copy_conting_class
& operator=(BOOST_RV_REF(move_copy_conting_class
) ) {
51 move_copy_conting_class(const move_copy_conting_class
&) {
54 move_copy_conting_class
& operator=(BOOST_COPY_ASSIGN_REF(move_copy_conting_class
) ) {
60 unsigned int move_copy_conting_class::moves_count
= 0;
61 unsigned int move_copy_conting_class::copy_count
= 0;
63 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
67 // Making sure that internals of Boost.Move do not interfere with
68 // internals of Boost.Variant and in case of C++03 or C++98 compilation
70 typedef boost::variant
<int, move_copy_conting_class
> variant_I_type
;
71 variant_I_type v1
, v2
;
72 v1
= move_copy_conting_class();
77 move_copy_conting_class val
;
78 v2
= boost::move(val
);
81 variant_I_type
v3(boost::move(val
));
82 variant_I_type
v4(boost::move(v1
));
95 void run_moves_are_noexcept()
101 void run_const_rvalues()
112 typedef boost::variant
<int, move_copy_conting_class
> variant_I_type
;
113 variant_I_type v1
, v2
;
115 // Assuring that `move_copy_conting_class` was not created
116 BOOST_TEST(move_copy_conting_class::copy_count
== 0);
117 BOOST_TEST(move_copy_conting_class::moves_count
== 0);
119 v1
= move_copy_conting_class();
120 // Assuring that `move_copy_conting_class` was moved at least once
121 BOOST_TEST(move_copy_conting_class::moves_count
!= 0);
123 unsigned int total_count
= move_copy_conting_class::moves_count
+ move_copy_conting_class::copy_count
;
124 move_copy_conting_class var
;
126 move_copy_conting_class::moves_count
= 0;
127 move_copy_conting_class::copy_count
= 0;
129 // Assuring that move assignment operator moves/copyes value not more times than copy assignment operator
130 BOOST_TEST(total_count
<= move_copy_conting_class::moves_count
+ move_copy_conting_class::copy_count
);
132 move_copy_conting_class::moves_count
= 0;
133 move_copy_conting_class::copy_count
= 0;
134 v2
= boost::move(v1
);
135 // Assuring that `move_copy_conting_class` in v1 was moved at least once and was not copied
136 BOOST_TEST(move_copy_conting_class::moves_count
!= 0);
137 BOOST_TEST(move_copy_conting_class::copy_count
== 0);
139 v1
= move_copy_conting_class();
140 move_copy_conting_class::moves_count
= 0;
141 move_copy_conting_class::copy_count
= 0;
142 v2
= boost::move(v1
);
143 // Assuring that `move_copy_conting_class` in v1 was moved at least once and was not copied
144 BOOST_TEST(move_copy_conting_class::moves_count
!= 0);
145 BOOST_TEST(move_copy_conting_class::copy_count
== 0);
146 total_count
= move_copy_conting_class::moves_count
+ move_copy_conting_class::copy_count
;
147 move_copy_conting_class::moves_count
= 0;
148 move_copy_conting_class::copy_count
= 0;
150 // Assuring that move assignment operator moves/copyes value not more times than copy assignment operator
151 BOOST_TEST(total_count
<= move_copy_conting_class::moves_count
+ move_copy_conting_class::copy_count
);
154 typedef boost::variant
<move_copy_conting_class
, int> variant_II_type
;
156 move_copy_conting_class::moves_count
= 0;
157 move_copy_conting_class::copy_count
= 0;
158 v1
= boost::move(v3
);
159 // Assuring that `move_copy_conting_class` in v3 was moved at least once (v1 and v3 have different types)
160 BOOST_TEST(move_copy_conting_class::moves_count
!= 0);
162 move_copy_conting_class::moves_count
= 0;
163 move_copy_conting_class::copy_count
= 0;
164 v2
= boost::move(v1
);
165 // Assuring that `move_copy_conting_class` in v1 was moved at least once (v1 and v3 have different types)
166 BOOST_TEST(move_copy_conting_class::moves_count
!= 0);
168 move_copy_conting_class::moves_count
= 0;
169 move_copy_conting_class::copy_count
= 0;
170 variant_I_type
v5(boost::move(v1
));
171 // Assuring that `move_copy_conting_class` in v1 was moved at least once and was not copied
172 BOOST_TEST(move_copy_conting_class::moves_count
!= 0);
173 BOOST_TEST(move_copy_conting_class::copy_count
== 0);
175 total_count
= move_copy_conting_class::moves_count
+ move_copy_conting_class::copy_count
;
176 move_copy_conting_class::moves_count
= 0;
177 move_copy_conting_class::copy_count
= 0;
178 variant_I_type
v6(v1
);
179 // Assuring that move constructor moves/copyes value not more times than copy constructor
180 BOOST_TEST(total_count
<= move_copy_conting_class::moves_count
+ move_copy_conting_class::copy_count
);
185 move_copy_conting_class::moves_count
= 0;
186 move_copy_conting_class::copy_count
= 0;
188 move_copy_conting_class c1
;
189 typedef boost::variant
<int, move_copy_conting_class
> variant_I_type
;
190 variant_I_type
v1(boost::move(c1
));
192 // Assuring that `move_copy_conting_class` was not copyied
193 BOOST_TEST(move_copy_conting_class::copy_count
== 0);
194 BOOST_TEST(move_copy_conting_class::moves_count
> 0);
197 struct move_only_structure
{
198 move_only_structure(){}
199 move_only_structure(move_only_structure
&&){}
200 move_only_structure
& operator=(move_only_structure
&&) { return *this; }
203 move_only_structure(const move_only_structure
&);
204 move_only_structure
& operator=(const move_only_structure
&);
207 struct visitor_returning_move_only_type
: boost::static_visitor
<move_only_structure
> {
209 move_only_structure
operator()(const T
&) const {
210 return move_only_structure();
216 move_only_structure mo
;
217 boost::variant
<int, move_only_structure
> vi
, vi2(static_cast<move_only_structure
&&>(mo
));
218 BOOST_TEST(vi
.which() == 0);
219 BOOST_TEST(vi2
.which() == 1);
223 BOOST_TEST(vi
.which() == 0);
224 BOOST_TEST(vi2
.which() == 0);
226 vi
= static_cast<move_only_structure
&&>(mo
);
227 vi2
= static_cast<move_only_structure
&&>(mo
);
228 BOOST_TEST(vi
.which() == 1);
230 boost::variant
<move_only_structure
, int > rvi (1);
231 BOOST_TEST(rvi
.which() == 1);
232 rvi
= static_cast<move_only_structure
&&>(mo
);
233 BOOST_TEST(rvi
.which() == 0);
235 BOOST_TEST(rvi
.which() == 1);
236 rvi
= static_cast<boost::variant
<int, move_only_structure
>&&>(vi2
);
237 BOOST_TEST(rvi
.which() == 0);
239 move_only_structure from_visitor
= boost::apply_visitor(visitor_returning_move_only_type(), vi
);
243 void run_moves_are_noexcept() {
244 #if !defined(BOOST_NO_CXX11_NOEXCEPT) && (!defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || __GNUC_MINOR__ >= 8)
245 typedef boost::variant
<int, short, double> variant_noexcept_t
;
246 BOOST_TEST(boost::is_nothrow_move_assignable
<variant_noexcept_t
>::value
);
247 BOOST_TEST(boost::is_nothrow_move_constructible
<variant_noexcept_t
>::value
);
249 typedef boost::variant
<int, short, double, move_only_structure
> variant_except_t
;
250 BOOST_TEST(!boost::is_nothrow_move_assignable
<variant_except_t
>::value
);
251 BOOST_TEST(!boost::is_nothrow_move_constructible
<variant_except_t
>::value
);
255 inline const std::string
get_string() { return "test"; }
256 inline const boost::variant
<int, std::string
> get_variant() { return std::string("test"); }
257 inline const boost::variant
<std::string
, int> get_variant2() { return std::string("test"); }
259 void run_const_rvalues()
261 typedef boost::variant
<int, std::string
> variant_t
;
262 const variant_t
v1(get_string());
263 const variant_t
v2(get_variant());
264 const variant_t
v3(get_variant2());
266 variant_t v4
, v5
, v6
, v7
;
270 v7
= boost::move(v1
);
275 struct nothrow_copyable_throw_movable
{
276 nothrow_copyable_throw_movable(){}
277 nothrow_copyable_throw_movable(const nothrow_copyable_throw_movable
&) BOOST_NOEXCEPT
{}
278 nothrow_copyable_throw_movable
& operator=(const nothrow_copyable_throw_movable
&) BOOST_NOEXCEPT
{ return *this; }
279 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
280 nothrow_copyable_throw_movable(nothrow_copyable_throw_movable
&&) BOOST_NOEXCEPT_IF(false) {}
281 nothrow_copyable_throw_movable
& operator=(nothrow_copyable_throw_movable
&&) BOOST_NOEXCEPT_IF(false) { return *this; }
285 // This test is created to cover the following situation:
286 // https://svn.boost.org/trac/boost/ticket/8772
287 void run_tricky_compilation_test()
289 boost::variant
<int, nothrow_copyable_throw_movable
> v
;
290 v
= nothrow_copyable_throw_movable();
293 template <typename T
>
294 struct is_container
: boost::mpl::false_
{};
296 template <typename T
>
297 struct is_container
<boost::variant
<T
> > : is_container
<T
> {};
299 template <BOOST_VARIANT_ENUM_PARAMS(typename T
)>
300 struct is_container
<boost::variant
<BOOST_VARIANT_ENUM_PARAMS(T
)> >
301 : boost::mpl::bool_
<is_container
<T0
>::value
302 || is_container
<boost::variant
<BOOST_VARIANT_ENUM_SHIFTED_PARAMS(T
)> >::value
>
305 void run_is_container_compilation_test()
307 BOOST_TEST((!is_container
<boost::variant
<double, int> >::value
));
308 BOOST_TEST((!is_container
<boost::variant
<double, int, char> >::value
));
309 BOOST_TEST((!is_container
<boost::variant
<double, int, char, float> >::value
));
314 swap_ambiguouty_test_ns::swap_ambiguouty_test();
318 run_moves_are_noexcept();
319 run_tricky_compilation_test();
321 run_is_container_compilation_test();
323 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ > 6)
324 # ifdef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES
326 "Something wrong with macro definitions. GCC-4.7+ is known to work with variadic templates"
331 return boost::report_errors();