我正在尝试创建一个(非常)简单的消息传递系统,但我被c++ 03卡住了。在使用c++ 11特性之前,我已经解决了这个问题,但我再也没有这样的奢侈了。
目标编译器是Visual Studio 2008的(我认为是VC9?),但我没有它在我这个时候;这就是说,我可以通过简单地将g++强制到c++ 03标准来重现这个问题。
我已经设法在以下代码段中隔离了问题:
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 for " << 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));
}
…可以有任意数量的派生消息。
最让我印象深刻的错误
no known conversion for argument 1 from ‘BaseMessage’ to ‘DerivedMessage’
运行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 from ‘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 from ‘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 from ‘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 from ‘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 from ‘void ask(boost::function<void(Type)>) [with Type = DerivedMessage]’
testing03.cpp:34:50: required from here
/usr/include/boost/function/function_template.hpp:153:11: error: no match for call to ‘(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 for argument 1 from ‘BaseMessage’ to ‘DerivedMessage’
要清楚我在问什么,我怎么能改变我的ask
函数(这是我认为的问题是),这样我就可以调用函数与类型派生自一个共同的基础使用c++ 03?
您可以使用辅助函数来执行强制转换:
#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 {};
// we need a function to perform the `static_cast` from the base class
// to the 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 for "
<< boost::units::detail::demangle(typeid(Type).name())
<< std::endl;
// boost::function is a polymorphic function wrapper;
// it can store any Callable
// Here, we store the actual function to be called, `f`, inside the
// function object returned from `bind`.
// The `bind` expression returns a function object that invokes
// `invoke_binder` which invokes the bound function `f`.
subscribers[boost::units::detail::demangle(typeid(Type).name())]
= boost::bind(&invoke_binder<Type, F>, f, _1);
}
注意回调函数签名的变化;此外,对ask
的调用现在直接使用函数指针。如果它是一个bind
表达式有一些错误,我不知道是什么原因。
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 i =
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);
}
稍微复杂一点,但没有绑定表达式,如下:
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 for "
<< boost::units::detail::demangle(typeid(Type).name())
<< std::endl;
subscribers[boost::units::detail::demangle(typeid(Type).name())]
= wrapper<Type, F>(f);
}
奇怪的是,这甚至在使用ask<BaseMessage>(boost::bind(&testBase, _1));
调用时也有效。我怀疑被包装的绑定器被以一种特殊的方式处理,导致像这样调用第一个版本时出现错误。