лучший способ выполнить посещение вариантов с помощью лямбда-выражений

Я хочу встроить обращение к вариантным типам с помощью лямбда-выражений. На данный момент у меня есть следующий код:

struct Foo {
    boost::variant< boost::blank , int , string , vector< int >  > var;

    template 
    void ApplyOptionals( T& ref, IL&& intOption , SL&& stringOption , VL&& vectorOption ) {
        if (var.which() == 1) {
            intOption( ref , boost::get< int >(var) );
        } else if (var.which() ==2) {
            stringOption( ref , boost::get< string>(var) );
        } else if (var.which() == 3) {
            vectorOption( ref , boost::get< vector< int > >(var) );
        }
    };
};
// ...
myFooV.ApplyOptionals(
    obj,
    [](Obj& o, int v) -> void { cout << "int: " << v << endl; o.value = v; },
    [](Obj& o, string v) -> void{ cout << "string: " << v << endl; o.name = v; },
    [](Obj& o, vector< int >& v) -> void{ v.push_back(257); cout << " vector.. has elements: " << v.size() << endl; o.ids = v; }
);

Однако основным недостатком этого подхода является то, что он зависит от порядка параметров вариантного типа и не обнаруживает во время компиляции необработанные типы, такие как boost :: static_visitor

Могу ли я получить лучшее из обоих подходов?


Работая над отличным ответом от RMartinho, я пытаюсь решить эту ошибку, похоже, вариант считает, что вызовы operator () неоднозначны ( я использую g ++ 4.5.1, похоже, что он не может видеть лямбда-операторы.

глядя на этот вопрос запрос члена `... 'неоднозначен в g ++ , кажется, что c ++ не любит множественное наследование как способ обеспечения множественных перегрузок (даже если вызовы совершенно неоднозначны из-за разной сигнатуры)

#include 
#include 
#include 
#include 

using namespace std;

typedef boost::variant< boost::blank , int , string , vector< int >  > var_t;

template 
struct lambda_visitor : public boost::static_visitor, public Lambdas... {
    lambda_visitor(Lambdas... lambdas) : Lambdas(lambdas)... { }
};

template 
struct lambda_visitor : public boost::static_visitor {
    lambda_visitor() {}
};


template 
lambda_visitor make_lambda_visitor(Lambdas... lambdas) {
    return { lambdas... };
    // you can use the following instead if your compiler doesn't
    // support list-initialization yet
    // return lambda_visitor(lambdas...);
}

int main() {
    vector< int > vit;
    vit.push_back(7);

    var_t myFooV = vit;

    auto visitor = make_lambda_visitor(
        [](int v) -> void { cout << "int: " << v << endl; },
        [](string& v) -> void{ cout << "string: " << v << endl; },
        [](vector< int >& v) -> void{ v.push_back(27); boost::get< vector< int > >(myFooV).push_back(34);  cout << " vector.. has elements: " << v.size() << endl; }
    );

    cout << " and for the grand finale.. " << endl;

    boost::apply_visitor( visitor , myFooV );
};

Это дает мне примерно кучу ошибок повышения шаблонов, но отличительной частью является:

boost_1_46_0/boost/variant/variant.hpp:832:32: error: request for member ‘operator()’ is ambiguous
test2.cpp:44:54: error: candidates are: main()::&)>
test2.cpp:43:47: error:                 main()::
test2.cpp:42:55: error:                 main()::
boost_1_46_0/boost/variant/variant.hpp:832:32: error: return-statement with a value, in function returning 'void'

Это вся ошибка, на всякий случай, если мне не хватает другой важной информации:

boost_1_46_0/boost/variant/variant.hpp: In member function ‘boost::detail::variant::invoke_visitor::result_type boost::detail::variant::invoke_visitor::internal_visit(T&, int) [with T = std::vector, Visitor = lambda_visitor, main()::, main()::&)> >, boost::detail::variant::invoke_visitor::result_type = void]’:
boost_1_46_0/boost/variant/detail/visitation_impl.hpp:130:9:   instantiated from ‘typename Visitor::result_type boost::detail::variant::visitation_impl_invoke_impl(int, Visitor&, VoidPtrCV, T*, mpl_::true_) [with Visitor = boost::detail::variant::invoke_visitor, main()::, main()::&)> > >, VoidPtrCV = void*, T = std::vector, typename Visitor::result_type = void, mpl_::true_ = mpl_::bool_]’
boost_1_46_0/boost/variant/detail/visitation_impl.hpp:173:9:   instantiated from ‘typename Visitor::result_type boost::detail::variant::visitation_impl_invoke(int, Visitor&, VoidPtrCV, T*, NoBackupFlag, int) [with Visitor = boost::detail::variant::invoke_visitor, main()::, main()::&)> > >, VoidPtrCV = void*, T = std::vector, NoBackupFlag = boost::variant, std::vector >::has_fallback_type_, typename Visitor::result_type = void]’
boost_1_46_0/boost/variant/detail/visitation_impl.hpp:260:1:   instantiated from ‘typename Visitor::result_type boost::detail::variant::visitation_impl(int, int, Visitor&, VoidPtrCV, mpl_::false_, NoBackupFlag, Which*, step0*) [with Which = mpl_::int_<0>, step0 = boost::detail::variant::visitation_impl_step, boost::blank, boost::mpl::l_item, int, boost::mpl::l_item, std::basic_string, boost::mpl::l_item, std::vector, boost::mpl::l_end> > > > >, boost::mpl::l_iter >, Visitor = boost::detail::variant::invoke_visitor, main()::, main()::&)> > >, VoidPtrCV = void*, NoBackupFlag = boost::variant, std::vector >::has_fallback_type_, typename Visitor::result_type = void, mpl_::false_ = mpl_::bool_]’
boost_1_46_0/boost/variant/variant.hpp:1776:13:   instantiated from ‘static typename Visitor::result_type boost::variant::internal_apply_visitor_impl(int, int, Visitor&, VoidPtrCV) [with Visitor = boost::detail::variant::invoke_visitor, main()::, main()::&)> > >, VoidPtrCV = void*, T0_ = boost::blank, T1 = int, T2 = std::basic_string, T3 = std::vector, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_, typename Visitor::result_type = void]’
boost_1_46_0/boost/variant/variant.hpp:1787:13:   instantiated from ‘typename Visitor::result_type boost::variant::internal_apply_visitor(Visitor&) [with Visitor = boost::detail::variant::invoke_visitor, main()::, main()::&)> > >, T0_ = boost::blank, T1 = int, T2 = std::basic_string, T3 = std::vector, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_, typename Visitor::result_type = void]’
boost_1_46_0/boost/variant/variant.hpp:1810:52:   instantiated from ‘typename Visitor::result_type boost::variant::apply_visitor(Visitor&) [with Visitor = lambda_visitor, main()::, main()::&)> >, T0_ = boost::blank, T1 = int, T2 = std::basic_string, T3 = std::vector, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_, typename Visitor::result_type = void]’
boost_1_46_0/boost/variant/detail/apply_visitor_unary.hpp:60:43:   instantiated from ‘typename Visitor::result_type boost::apply_visitor(Visitor&, Visitable&) [with Visitor = lambda_visitor, main()::, main()::&)> >, Visitable = boost::variant, std::vector >, typename Visitor::result_type = void]’
test2.cpp:49:40:   instantiated from here
boost_1_46_0/boost/variant/variant.hpp:832:32: error: request for member ‘operator()’ is ambiguous
test2.cpp:44:54: error: candidates are: main()::&)>
test2.cpp:43:47: error:                 main()::
test2.cpp:42:55: error:                 main()::
boost_1_46_0/boost/variant/variant.hpp:832:32: error: return-statement with a value, in function returning 'void'

заключение:

Я хочу добавить окончательную версию этой утилиты, включая тесты:

lambda_visitor.h

#include 

namespace Variant {
    template 
    struct lambda_visitor;

    template 
    struct lambda_visitor< ReturnType, Lambda1, Lambdas...>
    : public lambda_visitor, public Lambda1 {
        using Lambda1::operator();
        using lambda_visitor< ReturnType, Lambdas...>::operator();
        typedef ReturnType ReturnType_t;

        lambda_visitor(Lambda1 l1, Lambdas... lambdas) : Lambda1(l1), lambda_visitor< ReturnType, Lambdas...> (lambdas...) {
        }

        lambda_visitor(Lambda1 && l1, Lambdas && ... lambdas) : Lambda1(l1), lambda_visitor< ReturnType, Lambdas...> (lambdas...) {
        }
    };

    template 
    struct lambda_visitor
    : public boost::static_visitor, public Lambda1 {
        using Lambda1::operator();
        typedef ReturnType ReturnType_t;

        lambda_visitor(Lambda1 l1) : boost::static_visitor (), Lambda1(l1) {
        }

        lambda_visitor(Lambda1 && l1) : boost::static_visitor (), Lambda1(l1) {
        }
    };

    template 
    struct lambda_visitor : public boost::static_visitor {

        typedef ReturnType ReturnType_t;
        lambda_visitor() : boost::static_visitor () {
        }
    };

    template 
    struct default_blank_visitor {

        typedef ReturnType ReturnType_t;
        inline ReturnType operator() (const boost::blank&) const {
            return (ReturnType) 0;
        };
    };

    template<>
    struct default_blank_visitor {

        typedef void ReturnType_t;
        inline void operator() (const boost::blank&) const {};
    };

    template 
    lambda_visitor, Lambdas...> make_lambda_visitor(Lambdas... lambdas) {
        return
        {
            default_blank_visitor (), lambdas...
        };
        // you can use the following instead if your compiler doesn't
        // support list-initialization yet
        //return lambda_visitor , Lambdas...>( default_blank_visitor(), lambdas...);
    };
    /*
    template 
    lambda_visitor, Lambdas...> make_lambda_visitor(Lambdas && ... lambdas) {
        return
        {
            default_blank_visitor (), lambdas...
        };
        // you can use the following instead if your compiler doesn't
        // support list-initialization yet
        //return lambda_visitor , Lambdas...>( default_blank_visitor(), lambdas...);
    };*/

    template 
    lambda_visitor make_lambda_visitor_override_blank(Lambdas... lambdas) {
        return
        {
            lambdas...
        };
        // you can use the following instead if your compiler doesn't
        // support list-initialization yet
        //return lambda_visitor(lambdas...);
    }


    namespace basic_usage 
    {
        struct Test
        {
            typedef boost::variant< boost::blank , int , double > variant_t;
            void run()
            {
                variant_t a, b, c;
                a = 42;
                b = 3.14159265;
                auto visitor = Variant::make_lambda_visitor( [](int v) -> int { return v+1; } , [](double v) -> int { return (int)v*2; } );
                int result = boost::apply_visitor(visitor, a);
                HAssertMsg( result == (42 + 1) , "unexpected");
                result = boost::apply_visitor( visitor , b);
                HAssertMsg( result == 6 , "unexpected");
                auto blankVisitor = Variant::make_lambda_visitor_override_blank( 
                [](int v) -> int { return -1; } 
                , [](double v) -> int { return -1; }
                , [](boost::blank ) -> int { return 0;} );
                result = boost::apply_visitor( blankVisitor , c);
                HAssertMsg( result == 0 , "unexpected");

                //same as previous case, but using lambda coalescing :-)
                auto blankVisitor2 = Variant::make_lambda_visitor_override_blank( 
                [](boost::variant< int , double >& v) -> int { return -1; } 
                , [](boost::blank ) -> int { return 0;} );
                result = boost::apply_visitor( blankVisitor2 , c);
                HAssertMsg( result == 0 , "unexpected");
                result = boost::apply_visitor( blankVisitor2 , a);
                HAssertMsg( result == -1 , "unexpected");
                result = boost::apply_visitor( blankVisitor2 , b);
                HAssertMsg( result == -1 , "unexpected");
            }
        };
    }
};

27
задан Community 23 May 2017 в 10:31
поделиться