Я хочу встроить обращение к вариантным типам с помощью лямбда-выражений. На данный момент у меня есть следующий код:
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'
Я хочу добавить окончательную версию этой утилиты, включая тесты:
#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");
}
};
}
};