boost_variant 0.1.0

Boost C++ library boost_variant packaged using Zanbil
Documentation
//-----------------------------------------------------------------------------
// boost-libs variant/test/auto_visitors.cpp source file
// See http://www.boost.org for updates, documentation, and revision history.
//-----------------------------------------------------------------------------
//
// Copyright (c) 2014-2025 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;
    }
};

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(boost::apply_visitor(lex_streamer_visitor)(v1) == "1");
    BOOST_TEST(boost::apply_visitor(lex_streamer(), v2) == "10");
    BOOST_TEST(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");

    std::string& ref_to_string = boost::apply_visitor(visitor_ref, v1);
    BOOST_TEST(ref_to_string == "1");

    lex_streamer_void lex_streamer_void_visitor;
    boost::apply_visitor(lex_streamer_void(), v1);
    boost::apply_visitor(lex_streamer_void(), v2);

    boost::apply_visitor(lex_streamer_void_visitor)(v2);


    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(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");

    std::string& ref_to_string = boost::apply_visitor(visitor_ref)(v1, v2);
    BOOST_TEST(ref_to_string == "1+10");

    boost::apply_visitor(lex_streamer_void(), v1, v2);
    boost::apply_visitor(lex_streamer_void(), v2, v1);

    boost::ignore_unused(lex_combine_visitor, visitor_ref);
}

void run3()
{
    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


int main()
{
    run_explicit();
    run();
    run2();
    run3();
    test_has_result_type_triat();

    return boost::report_errors();
}