blob: 3261e877fff3bbbbdbd58cefe2ea5bd216ae59c1 [file] [log] [blame]
//-----------------------------------------------------------------------------
// boost-libs variant/test/auto_visitors.cpp source file
// See http://www.boost.org for updates, documentation, and revision history.
//-----------------------------------------------------------------------------
//
// Copyright (c) 2014-2021 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 <boost/noncopyable.hpp>
#include <boost/core/ignore_unused.hpp>
namespace has_result_type_tests {
template <class T>
struct wrap {
typedef T result_type;
};
struct s1 : wrap<int> {};
struct s2 : wrap<int&> {};
struct s3 : wrap<const int&> {};
struct s4 {};
struct s5 : wrap<int*> {};
struct s6 : wrap<int**> {};
struct s7 : wrap<const int*> {};
struct s8 : wrap<boost::noncopyable> {};
struct s9 : wrap<boost::noncopyable&> {};
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
struct s10 : wrap<boost::noncopyable&&> {};
#endif
struct s11 : wrap<const boost::noncopyable&> {};
struct s12 : wrap<const boost::noncopyable*> {};
struct s13 : wrap<boost::noncopyable*> {};
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<s1>::value);
BOOST_TEST(has_result_type<s2>::value);
BOOST_TEST(has_result_type<s3>::value);
BOOST_TEST(!has_result_type<s4>::value);
BOOST_TEST(has_result_type<s5>::value);
BOOST_TEST(has_result_type<s6>::value);
BOOST_TEST(has_result_type<s7>::value);
BOOST_TEST(has_result_type<s8>::value);
BOOST_TEST(has_result_type<s9>::value);
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
BOOST_TEST(has_result_type<s10>::value);
#endif
BOOST_TEST(has_result_type<s11>::value);
BOOST_TEST(has_result_type<s12>::value);
BOOST_TEST(has_result_type<s13>::value);
BOOST_TEST(has_result_type<s14>::value);
BOOST_TEST(has_result_type<s15>::value);
BOOST_TEST(has_result_type<s16>::value);
}
struct lex_streamer_explicit: boost::static_visitor<std::string> {
template <class T>
const char* operator()(const T& ) {
return "10";
}
template <class T1, class T2>
const char* operator()(const T1& , const T2& ) {
return "100";
}
};
void run_explicit()
{
typedef boost::variant<int, std::string, double> 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 <iostream>
struct lex_streamer {
template <class T>
std::string operator()(const T& val) const {
return boost::lexical_cast<std::string>(val);
}
};
struct lex_streamer_void {
template <class T>
void operator()(const T& val) const {
std::cout << val << std::endl;
}
template <class T1, class T2>
void operator()(const T1& val, const T2& val2) const {
std::cout << val << '+' << val2 << std::endl;
}
template <class T1, class T2, class T3>
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 <class T>
const char* operator()(const T& /*val*/) const {
return "fail";
}
template <class T1, class T2>
const char* operator()(const T1& /*v1*/, const T2& /*v2*/) const {
return "fail2";
}
template <class T1, class T2, class T3>
const char* operator()(const T1& /*v1*/, const T2& /*v2*/, const T3& /*v3*/) const {
return "fail3";
}
template <class T>
std::string& operator()(const T& val) {
res = boost::lexical_cast<std::string>(val);
return res;
}
template <class T1, class T2>
std::string& operator()(const T1& v1, const T2& v2) {
res = boost::lexical_cast<std::string>(v1) + "+" + boost::lexical_cast<std::string>(v2);
return res;
}
template <class T1, class T2, class T3>
std::string& operator()(const T1& v1, const T2& v2, const T3& v3) {
res = boost::lexical_cast<std::string>(v1) + "+" + boost::lexical_cast<std::string>(v2)
+ "+" + boost::lexical_cast<std::string>(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<int, std::string, double> 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<std::string>(v); }, v1) == "1");
BOOST_TEST(boost::apply_visitor([](auto v) { return boost::lexical_cast<std::string>(v); }, v2) == "10");
// Retun type must be the same in all instances, so this code does not compile
//boost::variant<int, short, unsigned> 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 <class T1, class T2>
std::string operator()(const T1& v1, const T2& v2) const {
return boost::lexical_cast<std::string>(v1) + "+" + boost::lexical_cast<std::string>(v2);
}
template <class T1, class T2, class T3>
std::string operator()(const T1& v1, const T2& v2, const T3& v3) const {
return boost::lexical_cast<std::string>(v1) + "+"
+ boost::lexical_cast<std::string>(v2) + '+'
+ boost::lexical_cast<std::string>(v3);
}
};
void run2()
{
typedef boost::variant<int, std::string, double> 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<std::string>(v1) + "+"
+ boost::lexical_cast<std::string>(v2);
}
, v1
, v2
) == "1+10"
);
BOOST_TEST(
boost::apply_visitor(
[](auto v1, auto v2) {
return boost::lexical_cast<std::string>(v1) + "+"
+ boost::lexical_cast<std::string>(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<int, std::string, double> 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<std::string>(v1) + "+"
+ boost::lexical_cast<std::string>(v2) + "+"
+ boost::lexical_cast<std::string>(v3);
}
, v1
, v2
, v3
) == "1+10+100"
);
BOOST_TEST(
boost::apply_visitor(
[](auto v1, auto v2, auto v3) {
return boost::lexical_cast<std::string>(v1) + "+"
+ boost::lexical_cast<std::string>(v2) + "+"
+ boost::lexical_cast<std::string>(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();
}