//----------------------------------------------------------------------------- // boost-libs variant/test/recursive_variant_test.cpp source file // See http://www.boost.org for updates, documentation, and revision history. //----------------------------------------------------------------------------- // // Copyright (c) 2003 Eric Friedman, Itay Maman // Copyright (c) 2013-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) // This file is used in two test cases: // // 1) recursive_variant_test.cpp that tests recursive usage of variant // // 2) variant_noexcept_test that tests Boost.Variant ability to compile // and work with disabled exceptions #include "boost/core/lightweight_test.hpp" #include "boost/variant.hpp" #include "boost/mpl/vector.hpp" #include "boost/mpl/copy.hpp" #include #include #include #include #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) #include #endif // !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) struct printer : boost::static_visitor { template std::string operator()( const boost::variant &var) const { return boost::apply_visitor( printer(), var ); } template std::string operator()(const std::vector& vec) const { std::ostringstream ost; ost << "( "; typename std::vector::const_iterator it = vec.begin(); for (; it != vec.end(); ++it) ost << printer()( *it ); ost << ") "; return ost.str(); } #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) template struct indices {}; template std::string operator()(const std::tuple& tup, indices) const { std::ostringstream ost; ost << "( "; int a[] = {0, (ost << printer()( std::get(tup) ), 0)... }; (void)a; ost << ") "; return ost.str(); } template struct make_indices : make_indices {}; template struct make_indices<0, Is...> : indices {}; template std::string operator()(const std::tuple& tup) const { return printer()(tup, make_indices()); } #endif // !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) template std::string operator()(const T& operand) const { std::ostringstream ost; ost << operand << ' '; return ost.str(); } }; void test_recursive_variant() { typedef boost::make_recursive_variant< int , std::vector >::type var1_t; std::vector vec1; vec1.push_back(3); vec1.push_back(5); vec1.push_back(vec1); vec1.push_back(7); var1_t var1(vec1); std::string result1( printer()(var1) ); std::cout << "result1: " << result1 << '\n'; BOOST_TEST(result1 == "( 3 5 ( 3 5 ) 7 ) "); std::vector vec1_copy = vec1; vec1_copy.erase(vec1_copy.begin() + 2); vec1_copy.insert(vec1_copy.begin() + 2, vec1_copy); var1 = vec1_copy; result1 = printer()(var1); std::cout << "result1+: " << result1 << '\n'; BOOST_TEST(result1 == "( 3 5 ( 3 5 7 ) 7 ) "); // Uses move construction on compilers with rvalue references support result1 = printer()( var1_t( std::vector(vec1_copy) ) ); std::cout << "result1++: " << result1 << '\n'; BOOST_TEST(result1 == "( 3 5 ( 3 5 7 ) 7 ) "); var1_t vec1_another_copy(vec1_copy); vec1_copy[2].swap(vec1_another_copy); result1 = printer()( var1_t(vec1_copy) ); std::cout << "result1+++1: " << result1 << '\n'; BOOST_TEST(result1 == "( 3 5 ( 3 5 ( 3 5 7 ) 7 ) 7 ) "); result1 = printer()(vec1_another_copy); std::cout << "result1++2: " << result1 << '\n'; BOOST_TEST(result1 == "( 3 5 7 ) "); vec1_copy[2].swap(vec1_copy[2]); result1 = printer()( var1_t(vec1_copy) ); std::cout << "result1.2: " << result1 << '\n'; BOOST_TEST(result1 == "( 3 5 ( 3 5 ( 3 5 7 ) 7 ) 7 ) "); typedef boost::make_recursive_variant< boost::variant , std::vector >::type var2_t; std::vector vec2; vec2.push_back(boost::variant(3)); vec2.push_back(boost::variant(3.5)); vec2.push_back(vec2); vec2.push_back(boost::variant(7)); var2_t var2(vec2); std::string result2( printer()(var2) ); std::cout << "result2: " << result2 << '\n'; BOOST_TEST(result2 == "( 3 3.5 ( 3 3.5 ) 7 ) "); typedef boost::make_recursive_variant< int , std::vector< boost::variant< double , std::vector > > >::type var3_t; typedef boost::variant > var4_t; std::vector vec3; vec3.push_back(3); vec3.push_back(5); std::vector vec4; vec4.push_back(3.5); vec4.push_back(vec3); vec3.push_back(vec4); vec3.push_back(7); var4_t var4(vec3); std::string result3( printer()(var4) ); std::cout << "result2: " << result3 << '\n'; BOOST_TEST(result3 == "( 3 5 ( 3.5 ( 3 5 ) ) 7 ) "); typedef boost::make_recursive_variant< double, std::vector >::type var5_t; std::vector vec5; vec5.push_back(3.5); vec5.push_back(vec1); vec5.push_back(17.25); std::string result5( printer()(vec5) ); std::cout << "result5: " << result5 << '\n'; BOOST_TEST(result5 == "( 3.5 ( 3 5 ( 3 5 ) 7 ) 17.25 ) "); typedef boost::make_recursive_variant< int, std::map >::type var6_t; var6_t var6; #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) typedef boost::make_recursive_variant< int, std::tuple >::type var7_t; var7_t var7 = 0; // !!! Do not replace with `var7_t var7{0}` or `var7_t var7(0)` !!! var7 = std::tuple(1, var7); var7 = std::tuple(2, var7); std::string result7( printer()(var7) ); std::cout << "result7: " << result7 << '\n'; BOOST_TEST(result7 == "( 2 ( 1 0 ) ) "); #endif // !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) } void test_recursive_variant_over() { typedef boost::make_recursive_variant_over< boost::mpl::vector< int , std::vector > >::type var1_t; std::vector vec1; vec1.push_back(3); vec1.push_back(5); vec1.push_back(vec1); vec1.push_back(7); var1_t var1(vec1); std::string result1( printer()(var1) ); std::cout << "result1: " << result1 << '\n'; BOOST_TEST(result1 == "( 3 5 ( 3 5 ) 7 ) "); std::vector vec1_copy = vec1; vec1_copy.erase(vec1_copy.begin() + 2); vec1_copy.insert(vec1_copy.begin() + 2, vec1_copy); var1 = vec1_copy; result1 = printer()(var1); std::cout << "result1+: " << result1 << '\n'; BOOST_TEST(result1 == "( 3 5 ( 3 5 7 ) 7 ) "); // Uses move construction on compilers with rvalue references support result1 = printer()( var1_t( std::vector(vec1_copy) ) ); std::cout << "result1++: " << result1 << '\n'; BOOST_TEST(result1 == "( 3 5 ( 3 5 7 ) 7 ) "); var1_t vec1_another_copy(vec1_copy); vec1_copy[2].swap(vec1_another_copy); result1 = printer()( var1_t(vec1_copy) ); std::cout << "result1+++1: " << result1 << '\n'; BOOST_TEST(result1 == "( 3 5 ( 3 5 ( 3 5 7 ) 7 ) 7 ) "); result1 = printer()(vec1_another_copy); std::cout << "result1++2: " << result1 << '\n'; BOOST_TEST(result1 == "( 3 5 7 ) "); typedef boost::make_recursive_variant_over< boost::mpl::vector< boost::make_variant_over >::type , std::vector > >::type var2_t; std::vector vec2; vec2.push_back(boost::variant(3)); vec2.push_back(boost::variant(3.5)); vec2.push_back(vec2); vec2.push_back(boost::variant(7)); var2_t var2(vec2); std::string result2( printer()(var2) ); std::cout << "result2: " << result2 << '\n'; BOOST_TEST(result2 == "( 3 3.5 ( 3 3.5 ) 7 ) "); typedef boost::make_recursive_variant_over< boost::mpl::vector< int , std::vector< boost::make_variant_over< boost::mpl::vector< double , std::vector > >::type > > >::type var3_t; typedef boost::make_variant_over< boost::mpl::copy< boost::mpl::vector< double , std::vector > >::type >::type var4_t; std::vector vec3; vec3.push_back(3); vec3.push_back(5); std::vector vec4; vec4.push_back(3.5); vec4.push_back(vec3); vec3.push_back(vec4); vec3.push_back(7); var4_t var3(vec3); std::string result3( printer()(var3) ); std::cout << "result2: " << result3 << '\n'; BOOST_TEST(result3 == "( 3 5 ( 3.5 ( 3 5 ) ) 7 ) "); typedef boost::make_recursive_variant_over< boost::mpl::vector< double , std::vector > >::type var5_t; std::vector vec5; vec5.push_back(3.5); vec5.push_back(vec1); vec5.push_back(17.25); std::string result5( printer()(vec5) ); std::cout << "result5: " << result5 << '\n'; BOOST_TEST(result5 == "( 3.5 ( 3 5 ( 3 5 ) 7 ) 17.25 ) "); } int main() { test_recursive_variant(); test_recursive_variant_over(); return boost::report_errors(); }