c++ - Calling boost::function<void(BaseType)> with derived types -
i trying create (very) simple messaging system, stuck c++03. have solved problem before using c++11 features, not have such luxuries anymore.
the target compiler visual studio 2008's (which think vc9?), not have me @ time; said can reproduce problem forcing g++ c++03 standard.
i have managed isolate problem in following piece of code:
testing03.cpp
#include <iostream> #include <map> #include <boost/function.hpp> #include <boost/bind.hpp> #include <boost/units/detail/utility.hpp> struct basemessage {}; struct derivedmessage : basemessage {}; std::map<std::string, boost::function<void(basemessage)>> subscribers; template <typename type> void ask(boost::function<void(type)> function) { std::cout << "asking " << boost::units::detail::demangle(typeid(type).name()) << std::endl; subscribers[boost::units::detail::demangle(typeid(type).name())] = function; } void testbase(basemessage) { std::cout << "in testbase" << std::endl; } void testderived(derivedmessage) { std::cout << "in testderived" << std::endl; } int main() { ask<basemessage>(boost::bind(testbase, _1)); ask<derivedmessage>(boost::bind(testderived, _1)); } ...and there number of derived messages.
the error stands out me most
no known conversion argument 1 ‘basemessage’ ‘derivedmessage’ full output of running g++ -std=c++03 testing03.cpp
in instantiation of ‘static void boost::detail::function::void_function_obj_invoker1<functionobj, r, t0>::invoke(boost::detail::function::function_buffer&, t0) [with functionobj = boost::function<void(derivedmessage)>; r = void; t0 = basemessage]’: /usr/include/boost/function/function_template.hpp:934:38: required ‘void boost::function1<r, t1>::assign_to(functor) [with functor = boost::function<void(derivedmessage)>; r = void; t0 = basemessage]’ /usr/include/boost/function/function_template.hpp:722:7: required ‘boost::function1<r, t1>::function1(functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<functor>::value>::value, int>::type) [with functor = boost::function<void(derivedmessage)>; r = void; t0 = basemessage; typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<functor>::value>::value, int>::type = int]’ /usr/include/boost/function/function_template.hpp:1069:16: required ‘boost::function<r(t0)>::function(functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<functor>::value>::value, int>::type) [with functor = boost::function<void(derivedmessage)>; r = void; t0 = basemessage; typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<functor>::value>::value, int>::type = int]’ /usr/include/boost/function/function_template.hpp:1124:5: required ‘typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<functor>::value>::value, boost::function<r(t0)>&>::type boost::function<r(t0)>::operator=(functor) [with functor = boost::function<void(derivedmessage)>; r = void; t0 = basemessage; typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<functor>::value>::value, boost::function<r(t0)>&>::type = boost::function<void(basemessage)>&]’ testing03.cpp:18:67: required ‘void ask(boost::function<void(type)>) [with type = derivedmessage]’ testing03.cpp:34:50: required here /usr/include/boost/function/function_template.hpp:153:11: error: no match call ‘(boost::function<void(derivedmessage)>) (basemessage&)’ boost_function_return((*f)(boost_function_args)); ^ /usr/include/boost/function/function_template.hpp:1048:7: note: candidate is: class function<boost_function_partial_spec> ^ /usr/include/boost/function/function_template.hpp:761:17: note: boost::function1<r, t1>::result_type boost::function1<r, t1>::operator()(t0) const [with r = void; t0 = derivedmessage; boost::function1<r, t1>::result_type = void] result_type operator()(boost_function_parms) const ^ /usr/include/boost/function/function_template.hpp:761:17: note: no known conversion argument 1 ‘basemessage’ ‘derivedmessage’ to clear on i'm asking, how can change ask function (which believe problem is), can call functions types derived common base using c++03?
you can use helper function performs cast:
#include <map> #include <boost/function.hpp> #include <boost/bind.hpp> #include <boost/units/detail/utility.hpp> #include <boost/smart_ptr.hpp> struct basemessage {}; struct derivedmessage : basemessage {}; // need function perform `static_cast` base class // derived class template<class t, class f> void invoke_binder(f const& f, basemessage const& m) { f( static_cast<t const&>(m) ); } std::map<std::string, boost::function<void(basemessage const&)> > subscribers; template <typename type, class f> void ask(f const& f) { std::cout << "asking " << boost::units::detail::demangle(typeid(type).name()) << std::endl; // boost::function polymorphic function wrapper; // can store callable // here, store actual function called, `f`, inside // function object returned `bind`. // `bind` expression returns function object invokes // `invoke_binder` invokes bound function `f`. subscribers[boost::units::detail::demangle(typeid(type).name())] = boost::bind(&invoke_binder<type, f>, f, _1); } note change in signature of callbacks; also, calls ask directly use function pointer. there's error if it's bind expression -- , don't know causes it.
void testbase(basemessage const&) { std::cout << "in testbase" << std::endl; } void testderived(derivedmessage const&) { std::cout << "in testderived" << std::endl; } template<class t> void call(t const& p) { subscribers_t::const_iterator = subscribers.find( boost::units::detail::demangle(typeid(t).name()) ); if(i != subscribers.end()) { (i->second)(p); }else { // error handling } } int main() { ask<basemessage>(&testbase); ask<derivedmessage>(&testderived); derivedmessage d; call(d); basemessage b; call(b); } a bit more complicated, w/o bind expressions, following:
template<class type, class f> struct wrapper { f f; wrapper(f const& f) : f(f) {} void operator()(basemessage const& p) { return f( static_cast<type const&>(p) ); } }; template <typename type, class f> void ask(f const& f) { std::cout << "asking " << boost::units::detail::demangle(typeid(type).name()) << std::endl; subscribers[boost::units::detail::demangle(typeid(type).name())] = wrapper<type, f>(f); } and strangely enough, works when called ask<basemessage>(boost::bind(&testbase, _1));. suspect wrapped binder treated in special way causes error in first version when called this.
Comments
Post a Comment