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

Popular posts from this blog

php - SPIP: From Tag directly to an article -

jquery - isAjaxRequest always return false -

ruby on rails - In a controller spec, how to find a specific tag in the generated view? -