diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 12deacd..9b023e9 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include @@ -78,9 +80,11 @@ namespace boost { union any_pointer { void* obj_ptr; + const void* const_obj_ptr; void (*func_ptr)(); explicit any_pointer(void* p) : obj_ptr(p) {} + explicit any_pointer(const void* p) : const_obj_ptr(p) {} explicit any_pointer(void (*p)()) : func_ptr(p) {} }; @@ -109,7 +113,11 @@ namespace boost { }; // The operation type to perform on the given functor/function pointer - enum functor_manager_operation_type { clone_functor, destroy_functor }; + enum functor_manager_operation_type { + clone_functor, + destroy_functor, + retrieve_type_info + }; // Tags used to decide between function and function object pointers. struct function_ptr_tag {}; @@ -140,8 +148,10 @@ namespace boost { { if (op == clone_functor) return function_ptr; - else + else if (op == destroy_functor) return any_pointer(static_cast(0)); + else + return any_pointer(&typeid(Functor)); } // For function object pointers, we clone the pointer to each @@ -171,7 +181,7 @@ namespace boost { # endif // BOOST_NO_STD_ALLOCATOR return any_pointer(static_cast(new_f)); } - else { + else if (op == destroy_functor) { /* Cast from the void pointer to the functor pointer type */ functor_type* f = reinterpret_cast(function_obj_ptr.obj_ptr); @@ -190,8 +200,10 @@ namespace boost { return any_pointer(static_cast(0)); } + else { + return any_pointer(&typeid(Functor)); + } } - public: /* Dispatch to an appropriate manager based on whether we have a function pointer or a function object pointer. */ diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index b31921b..1573978 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -46,6 +46,8 @@ namespace boost { virtual R call(BOOST_FUNCTION_PARMS) const = 0; virtual BOOST_FUNCTION_INVOKER_BASE* clone() const = 0; virtual void destroy(BOOST_FUNCTION_INVOKER_BASE*) = 0; + virtual const std::type_info& type() const = 0; + virtual any_pointer pointer() const = 0; }; #endif // BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS @@ -113,8 +115,18 @@ namespace boost { # endif // BOOST_NO_STD_ALLOCATOR } + virtual const std::type_info& type() const + { + return typeid(FunctionPtr); + } + + virtual any_pointer pointer() const + { + return any_pointer(reinterpret_cast(function_ptr)); + } + private: - FunctionPtr function_ptr; + mutable FunctionPtr function_ptr; #else static R invoke(any_pointer function_ptr BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS) @@ -190,8 +202,18 @@ namespace boost { # endif // BOOST_NO_STD_ALLOCATOR } + virtual const std::type_info& type() const + { + return typeid(FunctionPtr); + } + + virtual any_pointer pointer() const + { + return any_pointer(reinterpret_cast(function_ptr)); + } + private: - FunctionPtr function_ptr; + mutable FunctionPtr function_ptr; # else static unusable invoke(any_pointer function_ptr BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS) @@ -268,6 +290,16 @@ namespace boost { #endif // BOOST_NO_STD_ALLOCATOR } + virtual const std::type_info& type() const + { + return typeid(FunctionObj); + } + + virtual any_pointer pointer() const + { + return any_pointer(&function_obj); + } + private: mutable FunctionObj function_obj; #else @@ -346,6 +378,16 @@ namespace boost { # endif // BOOST_NO_STD_ALLOCATOR } + virtual const std::type_info& type() const + { + return typeid(FunctionObj); + } + + virtual any_pointer pointer() const + { + return any_pointer(&function_obj); + } + private: mutable FunctionObj function_obj; # else @@ -601,7 +643,73 @@ namespace boost { #endif // BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS } + const std::type_info& target_type() const + { + if (this->empty()) + return typeid(void); + else { +#ifdef BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS + impl_type* i = reinterpret_cast(impl); + return i->type(); +#else + detail::function::any_pointer p = + manager(functor, detail::function::retrieve_type_info); + return *static_cast(p.const_obj_ptr); +#endif // BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS + } + } + + template + To& cast(To* = 0) + { + assert(typeid(To) != typeid(void)); + assert(typeid(To) == this->target_type()); + typedef typename detail::function::IF<(is_pointer::value), + detail::function::function_ptr_tag, + detail::function::function_obj_tag>::type tag; + +#ifdef BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS + impl_type* i = reinterpret_cast(impl); + return cast_helper(i->pointer(), tag()); +#else + return cast_helper(functor, tag()); +#endif // BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS + } + + template + const To& cast(To* = 0) const + { + assert(typeid(To) != typeid(void)); + assert(typeid(To) == this->target_type()); + typedef typename detail::function::IF<(is_pointer::value), + detail::function::function_ptr_tag, + detail::function::function_obj_tag>::type tag; + +#ifdef BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS + impl_type* i = reinterpret_cast(impl); + return cast_helper(i->pointer(), tag()); +#else + return cast_helper(functor, tag()); +#endif // BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS + } + private: + template + To& cast_helper(detail::function::any_pointer p, + detail::function::function_ptr_tag, + To* = 0) const + { + return reinterpret_cast(p.func_ptr); + } + + template + To& cast_helper(detail::function::any_pointer p, + detail::function::function_obj_tag, + To* = 0) const + { + return *static_cast(p.obj_ptr); + } + void assign_to_own(const BOOST_FUNCTION_FUNCTION& f) { if (!f.empty()) { @@ -731,6 +839,36 @@ namespace boost { { f1.swap(f2); } + + template + inline To& function_cast(BOOST_FUNCTION_FUNCTION< + R BOOST_FUNCTION_COMMA + BOOST_FUNCTION_TEMPLATE_ARGS , + Policy, + Mixin, + Allocator + >& f, + To* = 0) + { + return f.template cast(); + } + + template + inline const To& function_cast(const BOOST_FUNCTION_FUNCTION< + R BOOST_FUNCTION_COMMA + BOOST_FUNCTION_TEMPLATE_ARGS , + Policy, + Mixin, + Allocator + >& f, + To* = 0) + { + return f.template cast(); + } } // Cleanup after ourselves...