//----------------------------------------------------------------------------- // boost-libs variant/test/auto_visitors.cpp source file // See http://www.boost.org for updates, documentation, and revision history. //----------------------------------------------------------------------------- // // Copyright (c) 2014-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/variant/multivisitors.hpp" #include "boost/lexical_cast.hpp" #include #include namespace has_result_type_tests { template struct wrap { typedef T result_type; }; struct s1 : wrap {}; struct s2 : wrap {}; struct s3 : wrap {}; struct s4 {}; struct s5 : wrap {}; struct s6 : wrap {}; struct s7 : wrap {}; struct s8 : wrap {}; struct s9 : wrap {}; #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES struct s10 : wrap {}; #endif struct s11 : wrap {}; struct s12 : wrap {}; struct s13 : wrap {}; struct s14 { typedef int result_type; }; struct s15 { typedef int& result_type; }; struct s16 { typedef const int& result_type; }; } void test_has_result_type_triat() { using namespace has_result_type_tests; using boost::detail::variant::has_result_type; BOOST_TEST(has_result_type::value); BOOST_TEST(has_result_type::value); BOOST_TEST(has_result_type::value); BOOST_TEST(!has_result_type::value); BOOST_TEST(has_result_type::value); BOOST_TEST(has_result_type::value); BOOST_TEST(has_result_type::value); BOOST_TEST(has_result_type::value); BOOST_TEST(has_result_type::value); #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES BOOST_TEST(has_result_type::value); #endif BOOST_TEST(has_result_type::value); BOOST_TEST(has_result_type::value); BOOST_TEST(has_result_type::value); BOOST_TEST(has_result_type::value); BOOST_TEST(has_result_type::value); BOOST_TEST(has_result_type::value); } 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_TEST(boost::apply_visitor(visitor_ref, v2).c_str() == std::string("10")); BOOST_TEST(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_TEST(true); } void run2() { BOOST_TEST(true); } void run3() { BOOST_TEST(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_TEST_IF_HAS_VARIADIC(x) BOOST_TEST(x) #else # define BOOST_TEST_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_TEST(boost::apply_visitor(lex_streamer(), v1) == "1"); BOOST_TEST_IF_HAS_VARIADIC(boost::apply_visitor(lex_streamer_visitor)(v1) == "1"); BOOST_TEST(boost::apply_visitor(lex_streamer(), v2) == "10"); BOOST_TEST_IF_HAS_VARIADIC(boost::apply_visitor(lex_streamer_visitor)(v2) == "10"); #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS BOOST_TEST(boost::apply_visitor([](auto v) { return boost::lexical_cast(v); }, v1) == "1"); BOOST_TEST(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_TEST(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_TEST(boost::apply_visitor(visitor_ref, v1) == "1"); BOOST_TEST(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_TEST(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 boost::ignore_unused(lex_streamer_visitor, visitor_ref, lex_streamer_void_visitor); } 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_TEST(boost::apply_visitor(lex_combine(), v1, v2) == "1+10"); BOOST_TEST(boost::apply_visitor(lex_combine(), v2, v1) == "10+1"); BOOST_TEST_IF_HAS_VARIADIC(boost::apply_visitor(lex_combine_visitor)(v2, v1) == "10+1"); #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS BOOST_TEST( boost::apply_visitor( [](auto v1, auto v2) { return boost::lexical_cast(v1) + "+" + boost::lexical_cast(v2); } , v1 , v2 ) == "1+10" ); BOOST_TEST( 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_TEST(boost::apply_visitor(visitor_ref, v1, v2) == "1+10"); BOOST_TEST(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_TEST(ref_to_string == "1+10"); #endif boost::apply_visitor(lex_streamer_void(), v1, v2); boost::apply_visitor(lex_streamer_void(), v2, v1); boost::ignore_unused(lex_combine_visitor, visitor_ref); } #undef BOOST_TEST_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_TEST(boost::apply_visitor(lex_combine(), v1, v2, v3) == "1+10+100"); BOOST_TEST(boost::apply_visitor(lex_combine(), v2, v1, v3) == "10+1+100"); BOOST_TEST(boost::apply_visitor(lex_combine_visitor)(v2, v1, v3) == "10+1+100"); #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS BOOST_TEST( 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_TEST( 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_TEST(boost::apply_visitor(visitor_ref, v1, v2) == "1+10"); BOOST_TEST(boost::apply_visitor(visitor_ref)(v2, v1) == "10+1"); std::string& ref_to_string = boost::apply_visitor(visitor_ref, v1, v2); BOOST_TEST(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 main() { run_explicit(); run(); run2(); run3(); test_has_result_type_triat(); return boost::report_errors(); }