//----------------------------------------------------------------------------- // boost-libs variant/test/rvalue_test.cpp source file // See http://www.boost.org for updates, documentation, and revision history. //----------------------------------------------------------------------------- // // Copyright (c) 2012-2019 Antony Polukhin // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include "boost/config.hpp" #include "boost/core/lightweight_test.hpp" #include "boost/variant.hpp" #include "boost/type_traits/is_nothrow_move_assignable.hpp" #include "boost/mpl/bool.hpp" #include #include namespace swap_ambiguouty_test_ns { struct A {}; struct B {}; void swap_ambiguouty_test() { // If boost::blank is not used, then it compiles. typedef boost::variant Variant; Variant v1, v2; swap(v1, v2); } } // namespace swap_ambiguouty_test_ns // Most part of tests from this file require rvalue references support class move_copy_conting_class { public: static unsigned int moves_count; static unsigned int copy_count; move_copy_conting_class(){} move_copy_conting_class(BOOST_RV_REF(move_copy_conting_class) ) { ++ moves_count; } move_copy_conting_class& operator=(BOOST_RV_REF(move_copy_conting_class) ) { ++ moves_count; return *this; } move_copy_conting_class(const move_copy_conting_class&) { ++ copy_count; } move_copy_conting_class& operator=(BOOST_COPY_ASSIGN_REF(move_copy_conting_class) ) { ++ copy_count; return *this; } }; unsigned int move_copy_conting_class::moves_count = 0; unsigned int move_copy_conting_class::copy_count = 0; #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES void run() { // Making sure that internals of Boost.Move do not interfere with // internals of Boost.Variant and in case of C++03 or C++98 compilation // is still possible. typedef boost::variant variant_I_type; variant_I_type v1, v2; v1 = move_copy_conting_class(); v2 = v1; v2 = boost::move(v1); v1.swap(v2); move_copy_conting_class val; v2 = boost::move(val); v2 = 10; variant_I_type v3(boost::move(val)); variant_I_type v4(boost::move(v1)); } void run1() { BOOST_TEST(true); } void run_move_only() { BOOST_TEST(true); } void run_moves_are_noexcept() { BOOST_TEST(true); } void run_const_rvalues() { BOOST_TEST(true); } #else void run() { typedef boost::variant variant_I_type; variant_I_type v1, v2; // Assuring that `move_copy_conting_class` was not created BOOST_TEST(move_copy_conting_class::copy_count == 0); BOOST_TEST(move_copy_conting_class::moves_count == 0); v1 = move_copy_conting_class(); // Assuring that `move_copy_conting_class` was moved at least once BOOST_TEST(move_copy_conting_class::moves_count != 0); unsigned int total_count = move_copy_conting_class::moves_count + move_copy_conting_class::copy_count; move_copy_conting_class var; v1 = 0; move_copy_conting_class::moves_count = 0; move_copy_conting_class::copy_count = 0; v1 = var; // Assuring that move assignment operator moves/copyes value not more times than copy assignment operator BOOST_TEST(total_count <= move_copy_conting_class::moves_count + move_copy_conting_class::copy_count); move_copy_conting_class::moves_count = 0; move_copy_conting_class::copy_count = 0; v2 = boost::move(v1); // Assuring that `move_copy_conting_class` in v1 was moved at least once and was not copied BOOST_TEST(move_copy_conting_class::moves_count != 0); BOOST_TEST(move_copy_conting_class::copy_count == 0); v1 = move_copy_conting_class(); move_copy_conting_class::moves_count = 0; move_copy_conting_class::copy_count = 0; v2 = boost::move(v1); // Assuring that `move_copy_conting_class` in v1 was moved at least once and was not copied BOOST_TEST(move_copy_conting_class::moves_count != 0); BOOST_TEST(move_copy_conting_class::copy_count == 0); total_count = move_copy_conting_class::moves_count + move_copy_conting_class::copy_count; move_copy_conting_class::moves_count = 0; move_copy_conting_class::copy_count = 0; v1 = v2; // Assuring that move assignment operator moves/copyes value not more times than copy assignment operator BOOST_TEST(total_count <= move_copy_conting_class::moves_count + move_copy_conting_class::copy_count); typedef boost::variant variant_II_type; variant_II_type v3; move_copy_conting_class::moves_count = 0; move_copy_conting_class::copy_count = 0; v1 = boost::move(v3); // Assuring that `move_copy_conting_class` in v3 was moved at least once (v1 and v3 have different types) BOOST_TEST(move_copy_conting_class::moves_count != 0); move_copy_conting_class::moves_count = 0; move_copy_conting_class::copy_count = 0; v2 = boost::move(v1); // Assuring that `move_copy_conting_class` in v1 was moved at least once (v1 and v3 have different types) BOOST_TEST(move_copy_conting_class::moves_count != 0); move_copy_conting_class::moves_count = 0; move_copy_conting_class::copy_count = 0; variant_I_type v5(boost::move(v1)); // Assuring that `move_copy_conting_class` in v1 was moved at least once and was not copied BOOST_TEST(move_copy_conting_class::moves_count != 0); BOOST_TEST(move_copy_conting_class::copy_count == 0); total_count = move_copy_conting_class::moves_count + move_copy_conting_class::copy_count; move_copy_conting_class::moves_count = 0; move_copy_conting_class::copy_count = 0; variant_I_type v6(v1); // Assuring that move constructor moves/copyes value not more times than copy constructor BOOST_TEST(total_count <= move_copy_conting_class::moves_count + move_copy_conting_class::copy_count); } void run1() { move_copy_conting_class::moves_count = 0; move_copy_conting_class::copy_count = 0; move_copy_conting_class c1; typedef boost::variant variant_I_type; variant_I_type v1(boost::move(c1)); // Assuring that `move_copy_conting_class` was not copyied BOOST_TEST(move_copy_conting_class::copy_count == 0); BOOST_TEST(move_copy_conting_class::moves_count > 0); } struct move_only_structure { move_only_structure(){} move_only_structure(move_only_structure&&){} move_only_structure& operator=(move_only_structure&&) { return *this; } private: move_only_structure(const move_only_structure&); move_only_structure& operator=(const move_only_structure&); }; struct visitor_returning_move_only_type: boost::static_visitor { template move_only_structure operator()(const T&) const { return move_only_structure(); } }; void run_move_only() { move_only_structure mo; boost::variant vi, vi2(static_cast(mo)); BOOST_TEST(vi.which() == 0); BOOST_TEST(vi2.which() == 1); vi = 10; vi2 = 10; BOOST_TEST(vi.which() == 0); BOOST_TEST(vi2.which() == 0); vi = static_cast(mo); vi2 = static_cast(mo); BOOST_TEST(vi.which() == 1); boost::variant rvi (1); BOOST_TEST(rvi.which() == 1); rvi = static_cast(mo); BOOST_TEST(rvi.which() == 0); rvi = 1; BOOST_TEST(rvi.which() == 1); rvi = static_cast&&>(vi2); BOOST_TEST(rvi.which() == 0); move_only_structure from_visitor = boost::apply_visitor(visitor_returning_move_only_type(), vi); (void)from_visitor; } void run_moves_are_noexcept() { #if !defined(BOOST_NO_CXX11_NOEXCEPT) && (!defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || __GNUC_MINOR__ >= 8) typedef boost::variant variant_noexcept_t; BOOST_TEST(boost::is_nothrow_move_assignable::value); BOOST_TEST(boost::is_nothrow_move_constructible::value); typedef boost::variant variant_except_t; BOOST_TEST(!boost::is_nothrow_move_assignable::value); BOOST_TEST(!boost::is_nothrow_move_constructible::value); #endif } inline const std::string get_string() { return "test"; } inline const boost::variant get_variant() { return std::string("test"); } inline const boost::variant get_variant2() { return std::string("test"); } void run_const_rvalues() { typedef boost::variant variant_t; const variant_t v1(get_string()); const variant_t v2(get_variant()); const variant_t v3(get_variant2()); variant_t v4, v5, v6, v7; v4 = get_string(); v5 = get_variant(); v6 = get_variant2(); v7 = boost::move(v1); } #endif struct nothrow_copyable_throw_movable { nothrow_copyable_throw_movable(){} nothrow_copyable_throw_movable(const nothrow_copyable_throw_movable&) BOOST_NOEXCEPT {} nothrow_copyable_throw_movable& operator=(const nothrow_copyable_throw_movable&) BOOST_NOEXCEPT { return *this; } #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES nothrow_copyable_throw_movable(nothrow_copyable_throw_movable&&) BOOST_NOEXCEPT_IF(false) {} nothrow_copyable_throw_movable& operator=(nothrow_copyable_throw_movable&&) BOOST_NOEXCEPT_IF(false) { return *this; } #endif }; // This test is created to cover the following situation: // https://svn.boost.org/trac/boost/ticket/8772 void run_tricky_compilation_test() { boost::variant v; v = nothrow_copyable_throw_movable(); } template struct is_container : boost::mpl::false_ {}; template struct is_container > : is_container {}; template struct is_container > : boost::mpl::bool_::value || is_container >::value> {}; void run_is_container_compilation_test() { BOOST_TEST((!is_container >::value)); BOOST_TEST((!is_container >::value)); BOOST_TEST((!is_container >::value)); } int main() { swap_ambiguouty_test_ns::swap_ambiguouty_test(); run(); run1(); run_move_only(); run_moves_are_noexcept(); run_tricky_compilation_test(); run_const_rvalues(); run_is_container_compilation_test(); #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ > 6) # ifdef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES BOOST_TEST(false && "Something wrong with macro definitions. GCC-4.7+ is known to work with variadic templates" ); # endif #endif return boost::report_errors(); }