williamr@2: // Boost.Function library williamr@2: williamr@2: // Copyright Douglas Gregor 2001-2006. Use, modification and williamr@2: // distribution is subject to the Boost Software License, Version williamr@2: // 1.0. (See accompanying file LICENSE_1_0.txt or copy at williamr@2: // http://www.boost.org/LICENSE_1_0.txt) williamr@2: williamr@2: // For more information, see http://www.boost.org williamr@2: williamr@2: #ifndef BOOST_FUNCTION_BASE_HEADER williamr@2: #define BOOST_FUNCTION_BASE_HEADER williamr@2: williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #ifndef BOOST_NO_SFINAE williamr@2: # include "boost/utility/enable_if.hpp" williamr@2: #else williamr@2: # include "boost/mpl/bool.hpp" williamr@2: #endif williamr@2: #include williamr@2: williamr@2: // Borrowed from Boost.Python library: determines the cases where we williamr@2: // need to use std::type_info::name to compare instead of operator==. williamr@2: # if (defined(__GNUC__) && __GNUC__ >= 3) \ williamr@2: || defined(_AIX) \ williamr@2: || ( defined(__sgi) && defined(__host_mips)) williamr@2: # include williamr@2: # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) \ williamr@2: (std::strcmp((X).name(),(Y).name()) == 0) williamr@2: # else williamr@2: # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y)) williamr@2: #endif williamr@2: williamr@2: #if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 || defined(__ICL) && __ICL <= 600 || defined(__MWERKS__) && __MWERKS__ < 0x2406 && !defined(BOOST_STRICT_CONFIG) williamr@2: # define BOOST_FUNCTION_TARGET_FIX(x) x williamr@2: #else williamr@2: # define BOOST_FUNCTION_TARGET_FIX(x) williamr@2: #endif // not MSVC williamr@2: williamr@2: #if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG) williamr@2: // Work around a compiler bug. williamr@2: // boost::python::objects::function has to be seen by the compiler before the williamr@2: // boost::function class template. williamr@2: namespace boost { namespace python { namespace objects { williamr@2: class function; williamr@2: }}} williamr@2: #endif williamr@2: williamr@2: #if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ williamr@2: || defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) \ williamr@2: || !(BOOST_STRICT_CONFIG || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540) williamr@2: # define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX williamr@2: #endif williamr@2: williamr@2: #if !BOOST_WORKAROUND(__BORLANDC__, < 0x600) williamr@2: # define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \ williamr@2: typename ::boost::enable_if_c<(::boost::type_traits::ice_not< \ williamr@2: (::boost::is_integral::value)>::value), \ williamr@2: Type>::type williamr@2: #else williamr@2: // BCC doesn't recognize this depends on a template argument and complains williamr@2: // about the use of 'typename' williamr@2: # define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \ williamr@2: ::boost::enable_if_c<(::boost::type_traits::ice_not< \ williamr@2: (::boost::is_integral::value)>::value), \ williamr@2: Type>::type williamr@2: #endif williamr@2: williamr@2: #if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX) williamr@2: namespace boost { williamr@2: williamr@2: #if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG) williamr@2: // The library shipping with MIPSpro 7.3.1.3m has a broken allocator williamr@2: class function_base; williamr@2: williamr@2: template > williamr@2: class function; williamr@2: #else williamr@2: template > williamr@2: class function; williamr@2: #endif williamr@2: williamr@2: template williamr@2: inline void swap(function& f1, williamr@2: function& f2) williamr@2: { williamr@2: f1.swap(f2); williamr@2: } williamr@2: williamr@2: } // end namespace boost williamr@2: #endif // have partial specialization williamr@2: williamr@2: namespace boost { williamr@2: namespace detail { williamr@2: namespace function { williamr@2: class X; williamr@2: williamr@2: /** williamr@2: * A buffer used to store small function objects in williamr@2: * boost::function. It is a union containing function pointers, williamr@2: * object pointers, and a structure that resembles a bound williamr@2: * member function pointer. williamr@2: */ williamr@2: union function_buffer williamr@2: { williamr@2: // For pointers to function objects williamr@2: void* obj_ptr; williamr@2: williamr@2: // For pointers to std::type_info objects williamr@2: // (get_functor_type_tag, check_functor_type_tag). williamr@2: const void* const_obj_ptr; williamr@2: williamr@2: // For function pointers of all kinds williamr@2: mutable void (*func_ptr)(); williamr@2: williamr@2: // For bound member pointers williamr@2: struct bound_memfunc_ptr_t { williamr@2: void (X::*memfunc_ptr)(int); williamr@2: void* obj_ptr; williamr@2: } bound_memfunc_ptr; williamr@2: williamr@2: // To relax aliasing constraints williamr@2: mutable char data; williamr@2: }; williamr@2: williamr@2: /** williamr@2: * The unusable class is a placeholder for unused function arguments williamr@2: * It is also completely unusable except that it constructable from williamr@2: * anything. This helps compilers without partial specialization to williamr@2: * handle Boost.Function objects returning void. williamr@2: */ williamr@2: struct unusable williamr@2: { williamr@2: unusable() {} williamr@2: template unusable(const T&) {} williamr@2: }; williamr@2: williamr@2: /* Determine the return type. This supports compilers that do not support williamr@2: * void returns or partial specialization by silently changing the return williamr@2: * type to "unusable". williamr@2: */ williamr@2: template struct function_return_type { typedef T type; }; williamr@2: williamr@2: template<> williamr@2: struct function_return_type williamr@2: { williamr@2: typedef unusable type; williamr@2: }; williamr@2: williamr@2: // The operation type to perform on the given functor/function pointer williamr@2: enum functor_manager_operation_type { williamr@2: clone_functor_tag, williamr@2: destroy_functor_tag, williamr@2: check_functor_type_tag, williamr@2: get_functor_type_tag williamr@2: }; williamr@2: williamr@2: // Tags used to decide between different types of functions williamr@2: struct function_ptr_tag {}; williamr@2: struct function_obj_tag {}; williamr@2: struct member_ptr_tag {}; williamr@2: struct function_obj_ref_tag {}; williamr@2: williamr@2: template williamr@2: class get_function_tag williamr@2: { williamr@2: typedef typename mpl::if_c<(is_pointer::value), williamr@2: function_ptr_tag, williamr@2: function_obj_tag>::type ptr_or_obj_tag; williamr@2: williamr@2: typedef typename mpl::if_c<(is_member_pointer::value), williamr@2: member_ptr_tag, williamr@2: ptr_or_obj_tag>::type ptr_or_obj_or_mem_tag; williamr@2: williamr@2: typedef typename mpl::if_c<(is_reference_wrapper::value), williamr@2: function_obj_ref_tag, williamr@2: ptr_or_obj_or_mem_tag>::type or_ref_tag; williamr@2: williamr@2: public: williamr@2: typedef or_ref_tag type; williamr@2: }; williamr@2: williamr@2: // The trivial manager does nothing but return the same pointer (if we williamr@2: // are cloning) or return the null pointer (if we are deleting). williamr@2: template williamr@2: struct reference_manager williamr@2: { williamr@2: static inline void williamr@2: get(const function_buffer& in_buffer, function_buffer& out_buffer, williamr@2: functor_manager_operation_type op) williamr@2: { williamr@2: switch (op) { williamr@2: case clone_functor_tag: williamr@2: out_buffer.obj_ptr = in_buffer.obj_ptr; williamr@2: return; williamr@2: williamr@2: case destroy_functor_tag: williamr@2: out_buffer.obj_ptr = 0; williamr@2: return; williamr@2: williamr@2: case check_functor_type_tag: williamr@2: { williamr@2: // DPG TBD: Since we're only storing a pointer, it's williamr@2: // possible that the user could ask for a base class or williamr@2: // derived class. Is that okay? williamr@2: const std::type_info& check_type = williamr@2: *static_cast(out_buffer.const_obj_ptr); williamr@2: if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F))) williamr@2: out_buffer.obj_ptr = in_buffer.obj_ptr; williamr@2: else williamr@2: out_buffer.obj_ptr = 0; williamr@2: } williamr@2: return; williamr@2: williamr@2: case get_functor_type_tag: williamr@2: out_buffer.const_obj_ptr = &typeid(F); williamr@2: return; williamr@2: } williamr@2: } williamr@2: }; williamr@2: williamr@2: /** williamr@2: * Determine if boost::function can use the small-object williamr@2: * optimization with the function object type F. williamr@2: */ williamr@2: template williamr@2: struct function_allows_small_object_optimization williamr@2: { williamr@2: BOOST_STATIC_CONSTANT williamr@2: (bool, williamr@2: value = ((sizeof(F) <= sizeof(function_buffer) && williamr@2: (alignment_of::value williamr@2: % alignment_of::value == 0)))); williamr@2: }; williamr@2: williamr@2: /** williamr@2: * The functor_manager class contains a static function "manage" which williamr@2: * can clone or destroy the given function/function object pointer. williamr@2: */ williamr@2: template williamr@2: struct functor_manager williamr@2: { williamr@2: private: williamr@2: typedef Functor functor_type; williamr@2: williamr@2: // For function pointers, the manager is trivial williamr@2: static inline void williamr@2: manager(const function_buffer& in_buffer, function_buffer& out_buffer, williamr@2: functor_manager_operation_type op, function_ptr_tag) williamr@2: { williamr@2: if (op == clone_functor_tag) williamr@2: out_buffer.func_ptr = in_buffer.func_ptr; williamr@2: else if (op == destroy_functor_tag) williamr@2: out_buffer.func_ptr = 0; williamr@2: else /* op == check_functor_type_tag */ { williamr@2: const std::type_info& check_type = williamr@2: *static_cast(out_buffer.const_obj_ptr); williamr@2: if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor))) williamr@2: out_buffer.obj_ptr = &in_buffer.func_ptr; williamr@2: else williamr@2: out_buffer.obj_ptr = 0; williamr@2: } williamr@2: } williamr@2: williamr@2: // Function objects that fit in the small-object buffer. williamr@2: static inline void williamr@2: manager(const function_buffer& in_buffer, function_buffer& out_buffer, williamr@2: functor_manager_operation_type op, mpl::true_) williamr@2: { williamr@2: if (op == clone_functor_tag) { williamr@2: const functor_type* in_functor = williamr@2: reinterpret_cast(&in_buffer.data); williamr@2: new ((void*)&out_buffer.data) functor_type(*in_functor); williamr@2: } else if (op == destroy_functor_tag) { williamr@2: // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type. williamr@2: reinterpret_cast(&out_buffer.data)->~Functor(); williamr@2: } else /* op == check_functor_type_tag */ { williamr@2: const std::type_info& check_type = williamr@2: *static_cast(out_buffer.const_obj_ptr); williamr@2: if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor))) williamr@2: out_buffer.obj_ptr = &in_buffer.data; williamr@2: else williamr@2: out_buffer.obj_ptr = 0; williamr@2: } williamr@2: } williamr@2: williamr@2: // Function objects that require heap allocation williamr@2: static inline void williamr@2: manager(const function_buffer& in_buffer, function_buffer& out_buffer, williamr@2: functor_manager_operation_type op, mpl::false_) williamr@2: { williamr@2: #ifndef BOOST_NO_STD_ALLOCATOR williamr@2: typedef typename Allocator::template rebind::other williamr@2: allocator_type; williamr@2: typedef typename allocator_type::pointer pointer_type; williamr@2: #else williamr@2: typedef functor_type* pointer_type; williamr@2: #endif // BOOST_NO_STD_ALLOCATOR williamr@2: williamr@2: # ifndef BOOST_NO_STD_ALLOCATOR williamr@2: allocator_type allocator; williamr@2: # endif // BOOST_NO_STD_ALLOCATOR williamr@2: williamr@2: if (op == clone_functor_tag) { williamr@2: // GCC 2.95.3 gets the CV qualifiers wrong here, so we williamr@2: // can't do the static_cast that we should do. williamr@2: const functor_type* f = williamr@2: (const functor_type*)(in_buffer.obj_ptr); williamr@2: williamr@2: // Clone the functor williamr@2: # ifndef BOOST_NO_STD_ALLOCATOR williamr@2: pointer_type copy = allocator.allocate(1); williamr@2: allocator.construct(copy, *f); williamr@2: williamr@2: // Get back to the original pointer type williamr@2: functor_type* new_f = static_cast(copy); williamr@2: # else williamr@2: functor_type* new_f = new functor_type(*f); williamr@2: # endif // BOOST_NO_STD_ALLOCATOR williamr@2: out_buffer.obj_ptr = new_f; williamr@2: } else if (op == destroy_functor_tag) { williamr@2: /* Cast from the void pointer to the functor pointer type */ williamr@2: functor_type* f = williamr@2: static_cast(out_buffer.obj_ptr); williamr@2: williamr@2: # ifndef BOOST_NO_STD_ALLOCATOR williamr@2: /* Cast from the functor pointer type to the allocator's pointer williamr@2: type */ williamr@2: pointer_type victim = static_cast(f); williamr@2: williamr@2: // Destroy and deallocate the functor williamr@2: allocator.destroy(victim); williamr@2: allocator.deallocate(victim, 1); williamr@2: # else williamr@2: delete f; williamr@2: # endif // BOOST_NO_STD_ALLOCATOR williamr@2: out_buffer.obj_ptr = 0; williamr@2: } else /* op == check_functor_type_tag */ { williamr@2: const std::type_info& check_type = williamr@2: *static_cast(out_buffer.const_obj_ptr); williamr@2: if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor))) williamr@2: out_buffer.obj_ptr = in_buffer.obj_ptr; williamr@2: else williamr@2: out_buffer.obj_ptr = 0; williamr@2: } williamr@2: } williamr@2: williamr@2: // For function objects, we determine whether the function williamr@2: // object can use the small-object optimization buffer or williamr@2: // whether we need to allocate it on the heap. williamr@2: static inline void williamr@2: manager(const function_buffer& in_buffer, function_buffer& out_buffer, williamr@2: functor_manager_operation_type op, function_obj_tag) williamr@2: { williamr@2: manager(in_buffer, out_buffer, op, williamr@2: mpl::bool_<(function_allows_small_object_optimization::value)>()); williamr@2: } williamr@2: williamr@2: public: williamr@2: /* Dispatch to an appropriate manager based on whether we have a williamr@2: function pointer or a function object pointer. */ williamr@2: static inline void williamr@2: manage(const function_buffer& in_buffer, function_buffer& out_buffer, williamr@2: functor_manager_operation_type op) williamr@2: { williamr@2: typedef typename get_function_tag::type tag_type; williamr@2: switch (op) { williamr@2: case get_functor_type_tag: williamr@2: out_buffer.const_obj_ptr = &typeid(functor_type); williamr@2: return; williamr@2: williamr@2: default: williamr@2: manager(in_buffer, out_buffer, op, tag_type()); williamr@2: return; williamr@2: } williamr@2: } williamr@2: }; williamr@2: williamr@2: // A type that is only used for comparisons against zero williamr@2: struct useless_clear_type {}; williamr@2: williamr@2: #ifdef BOOST_NO_SFINAE williamr@2: // These routines perform comparisons between a Boost.Function williamr@2: // object and an arbitrary function object (when the last williamr@2: // parameter is mpl::bool_) or against zero (when the williamr@2: // last parameter is mpl::bool_). They are only necessary williamr@2: // for compilers that don't support SFINAE. williamr@2: template williamr@2: bool williamr@2: compare_equal(const Function& f, const Functor&, int, mpl::bool_) williamr@2: { return f.empty(); } williamr@2: williamr@2: template williamr@2: bool williamr@2: compare_not_equal(const Function& f, const Functor&, int, williamr@2: mpl::bool_) williamr@2: { return !f.empty(); } williamr@2: williamr@2: template williamr@2: bool williamr@2: compare_equal(const Function& f, const Functor& g, long, williamr@2: mpl::bool_) williamr@2: { williamr@2: if (const Functor* fp = f.template target()) williamr@2: return function_equal(*fp, g); williamr@2: else return false; williamr@2: } williamr@2: williamr@2: template williamr@2: bool williamr@2: compare_equal(const Function& f, const reference_wrapper& g, williamr@2: int, mpl::bool_) williamr@2: { williamr@2: if (const Functor* fp = f.template target()) williamr@2: return fp == g.get_pointer(); williamr@2: else return false; williamr@2: } williamr@2: williamr@2: template williamr@2: bool williamr@2: compare_not_equal(const Function& f, const Functor& g, long, williamr@2: mpl::bool_) williamr@2: { williamr@2: if (const Functor* fp = f.template target()) williamr@2: return !function_equal(*fp, g); williamr@2: else return true; williamr@2: } williamr@2: williamr@2: template williamr@2: bool williamr@2: compare_not_equal(const Function& f, williamr@2: const reference_wrapper& g, int, williamr@2: mpl::bool_) williamr@2: { williamr@2: if (const Functor* fp = f.template target()) williamr@2: return fp != g.get_pointer(); williamr@2: else return true; williamr@2: } williamr@2: #endif // BOOST_NO_SFINAE williamr@2: williamr@2: /** williamr@2: * Stores the "manager" portion of the vtable for a williamr@2: * boost::function object. williamr@2: */ williamr@2: struct vtable_base williamr@2: { williamr@2: vtable_base() : manager(0) { } williamr@2: void (*manager)(const function_buffer& in_buffer, williamr@2: function_buffer& out_buffer, williamr@2: functor_manager_operation_type op); williamr@2: }; williamr@2: } // end namespace function williamr@2: } // end namespace detail williamr@2: williamr@2: /** williamr@2: * The function_base class contains the basic elements needed for the williamr@2: * function1, function2, function3, etc. classes. It is common to all williamr@2: * functions (and as such can be used to tell if we have one of the williamr@2: * functionN objects). williamr@2: */ williamr@2: class function_base williamr@2: { williamr@2: public: williamr@2: function_base() : vtable(0) { } williamr@2: williamr@2: /** Determine if the function is empty (i.e., has no target). */ williamr@2: bool empty() const { return !vtable; } williamr@2: williamr@2: /** Retrieve the type of the stored function object, or typeid(void) williamr@2: if this is empty. */ williamr@2: const std::type_info& target_type() const williamr@2: { williamr@2: if (!vtable) return typeid(void); williamr@2: williamr@2: detail::function::function_buffer type; williamr@2: vtable->manager(functor, type, detail::function::get_functor_type_tag); williamr@2: return *static_cast(type.const_obj_ptr); williamr@2: } williamr@2: williamr@2: template williamr@2: Functor* target() williamr@2: { williamr@2: if (!vtable) return 0; williamr@2: williamr@2: detail::function::function_buffer type_result; williamr@2: type_result.const_obj_ptr = &typeid(Functor); williamr@2: vtable->manager(functor, type_result, williamr@2: detail::function::check_functor_type_tag); williamr@2: return static_cast(type_result.obj_ptr); williamr@2: } williamr@2: williamr@2: template williamr@2: #if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300) williamr@2: const Functor* target( Functor * = 0 ) const williamr@2: #else williamr@2: const Functor* target() const williamr@2: #endif williamr@2: { williamr@2: if (!vtable) return 0; williamr@2: williamr@2: detail::function::function_buffer type_result; williamr@2: type_result.const_obj_ptr = &typeid(Functor); williamr@2: vtable->manager(functor, type_result, williamr@2: detail::function::check_functor_type_tag); williamr@2: // GCC 2.95.3 gets the CV qualifiers wrong here, so we williamr@2: // can't do the static_cast that we should do. williamr@2: return (const Functor*)(type_result.obj_ptr); williamr@2: } williamr@2: williamr@2: template williamr@2: bool contains(const F& f) const williamr@2: { williamr@2: #if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300) williamr@2: if (const F* fp = this->target( (F*)0 )) williamr@2: #else williamr@2: if (const F* fp = this->template target()) williamr@2: #endif williamr@2: { williamr@2: return function_equal(*fp, f); williamr@2: } else { williamr@2: return false; williamr@2: } williamr@2: } williamr@2: williamr@2: #if defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3 williamr@2: // GCC 3.3 and newer cannot copy with the global operator==, due to williamr@2: // problems with instantiation of function return types before it williamr@2: // has been verified that the argument types match up. williamr@2: template williamr@2: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) williamr@2: operator==(Functor g) const williamr@2: { williamr@2: if (const Functor* fp = target()) williamr@2: return function_equal(*fp, g); williamr@2: else return false; williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) williamr@2: operator!=(Functor g) const williamr@2: { williamr@2: if (const Functor* fp = target()) williamr@2: return !function_equal(*fp, g); williamr@2: else return true; williamr@2: } williamr@2: #endif williamr@2: williamr@2: public: // should be protected, but GCC 2.95.3 will fail to allow access williamr@2: detail::function::vtable_base* vtable; williamr@2: mutable detail::function::function_buffer functor; williamr@2: }; williamr@2: williamr@2: /** williamr@2: * The bad_function_call exception class is thrown when a boost::function williamr@2: * object is invoked williamr@2: */ williamr@2: class bad_function_call : public std::runtime_error williamr@2: { williamr@2: public: williamr@2: bad_function_call() : std::runtime_error("call to empty boost::function") {} williamr@2: }; williamr@2: williamr@2: #ifndef BOOST_NO_SFINAE williamr@2: inline bool operator==(const function_base& f, williamr@2: detail::function::useless_clear_type*) williamr@2: { williamr@2: return f.empty(); williamr@2: } williamr@2: williamr@2: inline bool operator!=(const function_base& f, williamr@2: detail::function::useless_clear_type*) williamr@2: { williamr@2: return !f.empty(); williamr@2: } williamr@2: williamr@2: inline bool operator==(detail::function::useless_clear_type*, williamr@2: const function_base& f) williamr@2: { williamr@2: return f.empty(); williamr@2: } williamr@2: williamr@2: inline bool operator!=(detail::function::useless_clear_type*, williamr@2: const function_base& f) williamr@2: { williamr@2: return !f.empty(); williamr@2: } williamr@2: #endif williamr@2: williamr@2: #ifdef BOOST_NO_SFINAE williamr@2: // Comparisons between boost::function objects and arbitrary function objects williamr@2: template williamr@2: inline bool operator==(const function_base& f, Functor g) williamr@2: { williamr@2: typedef mpl::bool_<(is_integral::value)> integral; williamr@2: return detail::function::compare_equal(f, g, 0, integral()); williamr@2: } williamr@2: williamr@2: template williamr@2: inline bool operator==(Functor g, const function_base& f) williamr@2: { williamr@2: typedef mpl::bool_<(is_integral::value)> integral; williamr@2: return detail::function::compare_equal(f, g, 0, integral()); williamr@2: } williamr@2: williamr@2: template williamr@2: inline bool operator!=(const function_base& f, Functor g) williamr@2: { williamr@2: typedef mpl::bool_<(is_integral::value)> integral; williamr@2: return detail::function::compare_not_equal(f, g, 0, integral()); williamr@2: } williamr@2: williamr@2: template williamr@2: inline bool operator!=(Functor g, const function_base& f) williamr@2: { williamr@2: typedef mpl::bool_<(is_integral::value)> integral; williamr@2: return detail::function::compare_not_equal(f, g, 0, integral()); williamr@2: } williamr@2: #else williamr@2: williamr@2: # if !(defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3) williamr@2: // Comparisons between boost::function objects and arbitrary function williamr@2: // objects. GCC 3.3 and before has an obnoxious bug that prevents this williamr@2: // from working. williamr@2: template williamr@2: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) williamr@2: operator==(const function_base& f, Functor g) williamr@2: { williamr@2: if (const Functor* fp = f.template target()) williamr@2: return function_equal(*fp, g); williamr@2: else return false; williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) williamr@2: operator==(Functor g, const function_base& f) williamr@2: { williamr@2: if (const Functor* fp = f.template target()) williamr@2: return function_equal(g, *fp); williamr@2: else return false; williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) williamr@2: operator!=(const function_base& f, Functor g) williamr@2: { williamr@2: if (const Functor* fp = f.template target()) williamr@2: return !function_equal(*fp, g); williamr@2: else return true; williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) williamr@2: operator!=(Functor g, const function_base& f) williamr@2: { williamr@2: if (const Functor* fp = f.template target()) williamr@2: return !function_equal(g, *fp); williamr@2: else return true; williamr@2: } williamr@2: # endif williamr@2: williamr@2: template williamr@2: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) williamr@2: operator==(const function_base& f, reference_wrapper g) williamr@2: { williamr@2: if (const Functor* fp = f.template target()) williamr@2: return fp == g.get_pointer(); williamr@2: else return false; williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) williamr@2: operator==(reference_wrapper g, const function_base& f) williamr@2: { williamr@2: if (const Functor* fp = f.template target()) williamr@2: return g.get_pointer() == fp; williamr@2: else return false; williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) williamr@2: operator!=(const function_base& f, reference_wrapper g) williamr@2: { williamr@2: if (const Functor* fp = f.template target()) williamr@2: return fp != g.get_pointer(); williamr@2: else return true; williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) williamr@2: operator!=(reference_wrapper g, const function_base& f) williamr@2: { williamr@2: if (const Functor* fp = f.template target()) williamr@2: return g.get_pointer() != fp; williamr@2: else return true; williamr@2: } williamr@2: williamr@2: #endif // Compiler supporting SFINAE williamr@2: williamr@2: namespace detail { williamr@2: namespace function { williamr@2: inline bool has_empty_target(const function_base* f) williamr@2: { williamr@2: return f->empty(); williamr@2: } williamr@2: williamr@2: #if BOOST_WORKAROUND(BOOST_MSVC, <= 1310) williamr@2: inline bool has_empty_target(const void*) williamr@2: { williamr@2: return false; williamr@2: } williamr@2: #else williamr@2: inline bool has_empty_target(...) williamr@2: { williamr@2: return false; williamr@2: } williamr@2: #endif williamr@2: } // end namespace function williamr@2: } // end namespace detail williamr@2: } // end namespace boost williamr@2: williamr@2: #undef BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL williamr@2: #undef BOOST_FUNCTION_COMPARE_TYPE_ID williamr@2: williamr@2: #endif // BOOST_FUNCTION_BASE_HEADER