381 lines
12 KiB
C++
381 lines
12 KiB
C++
//-----------------------------------------------------------------------------
|
|
// 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"
|
|
|
|
#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_CHECK(has_result_type<s1>::value);
|
|
BOOST_CHECK(has_result_type<s2>::value);
|
|
BOOST_CHECK(has_result_type<s3>::value);
|
|
BOOST_CHECK(!has_result_type<s4>::value);
|
|
BOOST_CHECK(has_result_type<s5>::value);
|
|
BOOST_CHECK(has_result_type<s6>::value);
|
|
BOOST_CHECK(has_result_type<s7>::value);
|
|
BOOST_CHECK(has_result_type<s8>::value);
|
|
BOOST_CHECK(has_result_type<s9>::value);
|
|
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
|
BOOST_CHECK(has_result_type<s10>::value);
|
|
#endif
|
|
BOOST_CHECK(has_result_type<s11>::value);
|
|
BOOST_CHECK(has_result_type<s12>::value);
|
|
BOOST_CHECK(has_result_type<s13>::value);
|
|
BOOST_CHECK(has_result_type<s14>::value);
|
|
BOOST_CHECK(has_result_type<s15>::value);
|
|
BOOST_CHECK(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_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 <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_CHECK_IF_HAS_VARIADIC(x) BOOST_CHECK(x)
|
|
#else
|
|
# define BOOST_CHECK_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_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<std::string>(v); }, v1) == "1");
|
|
BOOST_CHECK(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_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
|
|
|
|
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_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<std::string>(v1) + "+"
|
|
+ boost::lexical_cast<std::string>(v2);
|
|
}
|
|
, v1
|
|
, v2
|
|
) == "1+10"
|
|
);
|
|
BOOST_CHECK(
|
|
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_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);
|
|
|
|
boost::ignore_unused(lex_combine_visitor, visitor_ref);
|
|
}
|
|
|
|
#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<int, std::string, double> 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<std::string>(v1) + "+"
|
|
+ boost::lexical_cast<std::string>(v2) + "+"
|
|
+ boost::lexical_cast<std::string>(v3);
|
|
}
|
|
, v1
|
|
, v2
|
|
, v3
|
|
) == "1+10+100"
|
|
);
|
|
BOOST_CHECK(
|
|
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_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();
|
|
test_has_result_type_triat();
|
|
|
|
return 0;
|
|
}
|