//----------------------------------------------------------------------------- // boost-libs variant/test/auto_visitors.cpp source file // See http://www.boost.org for updates, documentation, and revision history. //----------------------------------------------------------------------------- // // Copyright (c) 2014-2015 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/test/minimal.hpp" #include "boost/variant.hpp" #include "boost/variant/multivisitors.hpp" #include "boost/lexical_cast.hpp" struct lex_streamer_explicit: boost::static_visitor { template const char* operator()(const T& ) { return "10"; } template const char* operator()(const T1& , const T2& ) { return "100"; } }; void run_explicit() { typedef boost::variant variant_type; variant_type v2("10"), v1("100"); lex_streamer_explicit visitor_ref; // Must return instance of std::string BOOST_CHECK(boost::apply_visitor(visitor_ref, v2).c_str() == std::string("10")); BOOST_CHECK(boost::apply_visitor(visitor_ref, v2, v1).c_str() == std::string("100")); } // Most part of tests from this file require decltype(auto) #ifdef BOOST_NO_CXX14_DECLTYPE_AUTO void run() { BOOST_CHECK(true); } void run2() { BOOST_CHECK(true); } void run3() { BOOST_CHECK(true); } #else #include struct lex_streamer { template std::string operator()(const T& val) const { return boost::lexical_cast(val); } }; struct lex_streamer_void { template void operator()(const T& val) const { std::cout << val << std::endl; } template void operator()(const T1& val, const T2& val2) const { std::cout << val << '+' << val2 << std::endl; } template void operator()(const T1& val, const T2& val2, const T3& val3) const { std::cout << val << '+' << val2 << '+' << val3 << std::endl; } }; struct lex_streamer2 { std::string res; template const char* operator()(const T& val) const { return "fail"; } template const char* operator()(const T1& v1, const T2& v2) const { return "fail2"; } template const char* operator()(const T1& v1, const T2& v2, const T3& v3) const { return "fail3"; } template std::string& operator()(const T& val) { res = boost::lexical_cast(val); return res; } template std::string& operator()(const T1& v1, const T2& v2) { res = boost::lexical_cast(v1) + "+" + boost::lexical_cast(v2); return res; } template std::string& operator()(const T1& v1, const T2& v2, const T3& v3) { res = boost::lexical_cast(v1) + "+" + boost::lexical_cast(v2) + "+" + boost::lexical_cast(v3); return res; } }; #ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES # define BOOST_CHECK_IF_HAS_VARIADIC(x) BOOST_CHECK(x) #else # define BOOST_CHECK_IF_HAS_VARIADIC(x) /**/ #endif void run() { typedef boost::variant variant_type; variant_type v1(1), v2("10"), v3(100.0); lex_streamer lex_streamer_visitor; BOOST_CHECK(boost::apply_visitor(lex_streamer(), v1) == "1"); BOOST_CHECK_IF_HAS_VARIADIC(boost::apply_visitor(lex_streamer_visitor)(v1) == "1"); BOOST_CHECK(boost::apply_visitor(lex_streamer(), v2) == "10"); BOOST_CHECK_IF_HAS_VARIADIC(boost::apply_visitor(lex_streamer_visitor)(v2) == "10"); #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS BOOST_CHECK(boost::apply_visitor([](auto v) { return boost::lexical_cast(v); }, v1) == "1"); BOOST_CHECK(boost::apply_visitor([](auto v) { return boost::lexical_cast(v); }, v2) == "10"); // Retun type must be the same in all instances, so this code does not compile //boost::variant v_diff_types(1); //BOOST_CHECK(boost::apply_visitor([](auto v) { return v; }, v_diff_types) == 1); boost::apply_visitor([](auto v) { std::cout << v << std::endl; }, v1); boost::apply_visitor([](auto v) { std::cout << v << std::endl; }, v2); #endif lex_streamer2 visitor_ref; BOOST_CHECK(boost::apply_visitor(visitor_ref, v1) == "1"); BOOST_CHECK(boost::apply_visitor(visitor_ref, v2) == "10"); #ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES std::string& ref_to_string = boost::apply_visitor(visitor_ref, v1); BOOST_CHECK(ref_to_string == "1"); #endif lex_streamer_void lex_streamer_void_visitor; boost::apply_visitor(lex_streamer_void(), v1); boost::apply_visitor(lex_streamer_void(), v2); #ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES boost::apply_visitor(lex_streamer_void_visitor)(v2); #endif } struct lex_combine { template std::string operator()(const T1& v1, const T2& v2) const { return boost::lexical_cast(v1) + "+" + boost::lexical_cast(v2); } template std::string operator()(const T1& v1, const T2& v2, const T3& v3) const { return boost::lexical_cast(v1) + "+" + boost::lexical_cast(v2) + '+' + boost::lexical_cast(v3); } }; void run2() { typedef boost::variant variant_type; variant_type v1(1), v2("10"), v3(100.0); lex_combine lex_combine_visitor; BOOST_CHECK(boost::apply_visitor(lex_combine(), v1, v2) == "1+10"); BOOST_CHECK(boost::apply_visitor(lex_combine(), v2, v1) == "10+1"); BOOST_CHECK_IF_HAS_VARIADIC(boost::apply_visitor(lex_combine_visitor)(v2, v1) == "10+1"); #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS BOOST_CHECK( boost::apply_visitor( [](auto v1, auto v2) { return boost::lexical_cast(v1) + "+" + boost::lexical_cast(v2); } , v1 , v2 ) == "1+10" ); BOOST_CHECK( boost::apply_visitor( [](auto v1, auto v2) { return boost::lexical_cast(v1) + "+" + boost::lexical_cast(v2); } , v2 , v1 ) == "10+1" ); boost::apply_visitor([](auto v1, auto v2) { std::cout << v1 << '+' << v2 << std::endl; }, v1, v2); boost::apply_visitor([](auto v1, auto v2) { std::cout << v1 << '+' << v2 << std::endl; }, v2, v1); #endif lex_streamer2 visitor_ref; BOOST_CHECK(boost::apply_visitor(visitor_ref, v1, v2) == "1+10"); BOOST_CHECK(boost::apply_visitor(visitor_ref, v2, v1) == "10+1"); #ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES std::string& ref_to_string = boost::apply_visitor(visitor_ref)(v1, v2); BOOST_CHECK(ref_to_string == "1+10"); #endif boost::apply_visitor(lex_streamer_void(), v1, v2); boost::apply_visitor(lex_streamer_void(), v2, v1); } #undef BOOST_CHECK_IF_HAS_VARIADIC void run3() { #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) typedef boost::variant variant_type; variant_type v1(1), v2("10"), v3(100); lex_combine lex_combine_visitor; BOOST_CHECK(boost::apply_visitor(lex_combine(), v1, v2, v3) == "1+10+100"); BOOST_CHECK(boost::apply_visitor(lex_combine(), v2, v1, v3) == "10+1+100"); BOOST_CHECK(boost::apply_visitor(lex_combine_visitor)(v2, v1, v3) == "10+1+100"); #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS BOOST_CHECK( boost::apply_visitor( [](auto v1, auto v2, auto v3) { return boost::lexical_cast(v1) + "+" + boost::lexical_cast(v2) + "+" + boost::lexical_cast(v3); } , v1 , v2 , v3 ) == "1+10+100" ); BOOST_CHECK( boost::apply_visitor( [](auto v1, auto v2, auto v3) { return boost::lexical_cast(v1) + "+" + boost::lexical_cast(v2) + "+" + boost::lexical_cast(v3); } , v3 , v1 , v3 ) == "100+1+100" ); boost::apply_visitor( [](auto v1, auto v2, auto v3) { std::cout << v1 << '+' << v2 << '+' << v3 << std::endl; }, v1, v2, v3 ); boost::apply_visitor( [](auto v1, auto v2, auto v3) { std::cout << v1 << '+' << v2 << '+' << v3 << std::endl; }, v2, v1, v3 ); #endif lex_streamer2 visitor_ref; BOOST_CHECK(boost::apply_visitor(visitor_ref, v1, v2) == "1+10"); BOOST_CHECK(boost::apply_visitor(visitor_ref)(v2, v1) == "10+1"); std::string& ref_to_string = boost::apply_visitor(visitor_ref, v1, v2); BOOST_CHECK(ref_to_string == "1+10"); lex_streamer_void lex_streamer_void_visitor; boost::apply_visitor(lex_streamer_void(), v1, v2, v1); boost::apply_visitor(lex_streamer_void(), v2, v1, v1); boost::apply_visitor(lex_streamer_void_visitor)(v2, v1, v1); #endif // !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) } #endif int test_main(int , char* []) { run_explicit(); run(); run2(); run3(); return 0; }