1 // Boost.Function library
3 // Copyright Douglas Gregor 2001-2006
4 // Copyright Emil Dotchevski 2007
5 // Use, modification and distribution is subject to the Boost Software License, Version 1.0.
6 // (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
9 // For more information, see http://www.boost.org
11 #ifndef BOOST_FUNCTION_BASE_HEADER
12 #define BOOST_FUNCTION_BASE_HEADER
19 #include <boost/config.hpp>
20 #include <boost/assert.hpp>
21 #include <boost/integer.hpp>
22 #include <boost/type_traits/has_trivial_copy.hpp>
23 #include <boost/type_traits/has_trivial_destructor.hpp>
24 #include <boost/type_traits/is_const.hpp>
25 #include <boost/type_traits/is_integral.hpp>
26 #include <boost/type_traits/is_volatile.hpp>
27 #include <boost/type_traits/composite_traits.hpp>
28 #include <boost/type_traits/ice.hpp>
29 #include <boost/ref.hpp>
30 #include <boost/mpl/if.hpp>
31 #include <boost/detail/workaround.hpp>
32 #include <boost/type_traits/alignment_of.hpp>
33 #ifndef BOOST_NO_SFINAE
34 # include "boost/utility/enable_if.hpp"
36 # include "boost/mpl/bool.hpp"
38 #include <boost/function_equal.hpp>
39 #include <boost/function/function_fwd.hpp>
41 #if defined(BOOST_MSVC)
42 # pragma warning( push )
43 # pragma warning( disable : 4793 ) // complaint about native code generation
44 # pragma warning( disable : 4127 ) // "conditional expression is constant"
47 // Define BOOST_FUNCTION_STD_NS to the namespace that contains type_info.
48 #ifdef BOOST_NO_STD_TYPEINFO
49 // Embedded VC++ does not have type_info in namespace std
50 # define BOOST_FUNCTION_STD_NS
52 # define BOOST_FUNCTION_STD_NS std
55 // Borrowed from Boost.Python library: determines the cases where we
56 // need to use std::type_info::name to compare instead of operator==.
57 # if (defined(__GNUC__) && __GNUC__ >= 3) \
59 || ( defined(__sgi) && defined(__host_mips))
61 # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) \
62 (std::strcmp((X).name(),(Y).name()) == 0)
64 # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y))
67 #if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 || defined(__ICL) && __ICL <= 600 || defined(__MWERKS__) && __MWERKS__ < 0x2406 && !defined(BOOST_STRICT_CONFIG)
68 # define BOOST_FUNCTION_TARGET_FIX(x) x
70 # define BOOST_FUNCTION_TARGET_FIX(x)
73 #if !BOOST_WORKAROUND(__BORLANDC__, < 0x5A0)
74 # define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \
75 typename ::boost::enable_if_c<(::boost::type_traits::ice_not< \
76 (::boost::is_integral<Functor>::value)>::value), \
79 // BCC doesn't recognize this depends on a template argument and complains
80 // about the use of 'typename'
81 # define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \
82 ::boost::enable_if_c<(::boost::type_traits::ice_not< \
83 (::boost::is_integral<Functor>::value)>::value), \
93 * A buffer used to store small function objects in
94 * boost::function. It is a union containing function pointers,
95 * object pointers, and a structure that resembles a bound
96 * member function pointer.
100 // For pointers to function objects
101 mutable void* obj_ptr;
103 // For pointers to std::type_info objects
105 // (get_functor_type_tag, check_functor_type_tag).
106 const BOOST_FUNCTION_STD_NS::type_info* type;
108 // Whether the type is const-qualified.
109 bool const_qualified;
110 // Whether the type is volatile-qualified.
111 bool volatile_qualified;
114 // For function pointers of all kinds
115 mutable void (*func_ptr)();
117 // For bound member pointers
118 struct bound_memfunc_ptr_t {
119 void (X::*memfunc_ptr)(int);
123 // For references to function objects. We explicitly keep
124 // track of the cv-qualifiers on the object referenced.
126 mutable void* obj_ptr;
127 bool is_const_qualified;
128 bool is_volatile_qualified;
131 // To relax aliasing constraints
136 * The unusable class is a placeholder for unused function arguments
137 * It is also completely unusable except that it constructable from
138 * anything. This helps compilers without partial specialization to
139 * handle Boost.Function objects returning void.
144 template<typename T> unusable(const T&) {}
147 /* Determine the return type. This supports compilers that do not support
148 * void returns or partial specialization by silently changing the return
149 * type to "unusable".
151 template<typename T> struct function_return_type { typedef T type; };
154 struct function_return_type<void>
156 typedef unusable type;
159 // The operation type to perform on the given functor/function pointer
160 enum functor_manager_operation_type {
164 check_functor_type_tag,
168 // Tags used to decide between different types of functions
169 struct function_ptr_tag {};
170 struct function_obj_tag {};
171 struct member_ptr_tag {};
172 struct function_obj_ref_tag {};
175 class get_function_tag
177 typedef typename mpl::if_c<(is_pointer<F>::value),
179 function_obj_tag>::type ptr_or_obj_tag;
181 typedef typename mpl::if_c<(is_member_pointer<F>::value),
183 ptr_or_obj_tag>::type ptr_or_obj_or_mem_tag;
185 typedef typename mpl::if_c<(is_reference_wrapper<F>::value),
186 function_obj_ref_tag,
187 ptr_or_obj_or_mem_tag>::type or_ref_tag;
190 typedef or_ref_tag type;
193 // The trivial manager does nothing but return the same pointer (if we
194 // are cloning) or return the null pointer (if we are deleting).
196 struct reference_manager
199 manage(const function_buffer& in_buffer, function_buffer& out_buffer,
200 functor_manager_operation_type op)
203 case clone_functor_tag:
204 out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr;
207 case move_functor_tag:
208 out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr;
209 in_buffer.obj_ref.obj_ptr = 0;
212 case destroy_functor_tag:
213 out_buffer.obj_ref.obj_ptr = 0;
216 case check_functor_type_tag:
218 const BOOST_FUNCTION_STD_NS::type_info& check_type
219 = *out_buffer.type.type;
221 // Check whether we have the same type. We can add
222 // cv-qualifiers, but we can't take them away.
223 if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F))
224 && (!in_buffer.obj_ref.is_const_qualified
225 || out_buffer.type.const_qualified)
226 && (!in_buffer.obj_ref.is_volatile_qualified
227 || out_buffer.type.volatile_qualified))
228 out_buffer.obj_ptr = in_buffer.obj_ref.obj_ptr;
230 out_buffer.obj_ptr = 0;
234 case get_functor_type_tag:
235 out_buffer.type.type = &typeid(F);
236 out_buffer.type.const_qualified = in_buffer.obj_ref.is_const_qualified;
237 out_buffer.type.volatile_qualified = in_buffer.obj_ref.is_volatile_qualified;
244 * Determine if boost::function can use the small-object
245 * optimization with the function object type F.
248 struct function_allows_small_object_optimization
250 BOOST_STATIC_CONSTANT
252 value = ((sizeof(F) <= sizeof(function_buffer) &&
253 (alignment_of<function_buffer>::value
254 % alignment_of<F>::value == 0))));
257 template <typename F,typename A>
258 struct functor_wrapper: public F, public A
260 functor_wrapper( F f, A a ):
266 functor_wrapper(const functor_wrapper& f) :
267 F(static_cast<const F&>(f)),
268 A(static_cast<const A&>(f))
274 * The functor_manager class contains a static function "manage" which
275 * can clone or destroy the given function/function object pointer.
277 template<typename Functor>
278 struct functor_manager_common
280 typedef Functor functor_type;
284 manage_ptr(const function_buffer& in_buffer, function_buffer& out_buffer,
285 functor_manager_operation_type op)
287 if (op == clone_functor_tag)
288 out_buffer.func_ptr = in_buffer.func_ptr;
289 else if (op == move_functor_tag) {
290 out_buffer.func_ptr = in_buffer.func_ptr;
291 in_buffer.func_ptr = 0;
292 } else if (op == destroy_functor_tag)
293 out_buffer.func_ptr = 0;
294 else if (op == check_functor_type_tag) {
295 const BOOST_FUNCTION_STD_NS::type_info& check_type
296 = *out_buffer.type.type;
297 if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
298 out_buffer.obj_ptr = &in_buffer.func_ptr;
300 out_buffer.obj_ptr = 0;
301 } else /* op == get_functor_type_tag */ {
302 out_buffer.type.type = &typeid(Functor);
303 out_buffer.type.const_qualified = false;
304 out_buffer.type.volatile_qualified = false;
308 // Function objects that fit in the small-object buffer.
310 manage_small(const function_buffer& in_buffer, function_buffer& out_buffer,
311 functor_manager_operation_type op)
313 if (op == clone_functor_tag || op == move_functor_tag) {
314 const functor_type* in_functor =
315 reinterpret_cast<const functor_type*>(&in_buffer.data);
316 new ((void*)&out_buffer.data) functor_type(*in_functor);
318 if (op == move_functor_tag) {
319 reinterpret_cast<functor_type*>(&in_buffer.data)->~Functor();
321 } else if (op == destroy_functor_tag) {
322 // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type.
323 reinterpret_cast<functor_type*>(&out_buffer.data)->~Functor();
324 } else if (op == check_functor_type_tag) {
325 const BOOST_FUNCTION_STD_NS::type_info& check_type
326 = *out_buffer.type.type;
327 if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
328 out_buffer.obj_ptr = &in_buffer.data;
330 out_buffer.obj_ptr = 0;
331 } else /* op == get_functor_type_tag */ {
332 out_buffer.type.type = &typeid(Functor);
333 out_buffer.type.const_qualified = false;
334 out_buffer.type.volatile_qualified = false;
339 template<typename Functor>
340 struct functor_manager
343 typedef Functor functor_type;
347 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
348 functor_manager_operation_type op, function_ptr_tag)
350 functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
353 // Function objects that fit in the small-object buffer.
355 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
356 functor_manager_operation_type op, mpl::true_)
358 functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
361 // Function objects that require heap allocation
363 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
364 functor_manager_operation_type op, mpl::false_)
366 if (op == clone_functor_tag) {
368 // GCC 2.95.3 gets the CV qualifiers wrong here, so we
369 // can't do the static_cast that we should do.
370 const functor_type* f =
371 (const functor_type*)(in_buffer.obj_ptr);
372 functor_type* new_f = new functor_type(*f);
373 out_buffer.obj_ptr = new_f;
374 } else if (op == move_functor_tag) {
375 out_buffer.obj_ptr = in_buffer.obj_ptr;
376 in_buffer.obj_ptr = 0;
377 } else if (op == destroy_functor_tag) {
378 /* Cast from the void pointer to the functor pointer type */
380 static_cast<functor_type*>(out_buffer.obj_ptr);
382 out_buffer.obj_ptr = 0;
383 } else if (op == check_functor_type_tag) {
384 const BOOST_FUNCTION_STD_NS::type_info& check_type
385 = *out_buffer.type.type;
386 if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
387 out_buffer.obj_ptr = in_buffer.obj_ptr;
389 out_buffer.obj_ptr = 0;
390 } else /* op == get_functor_type_tag */ {
391 out_buffer.type.type = &typeid(Functor);
392 out_buffer.type.const_qualified = false;
393 out_buffer.type.volatile_qualified = false;
397 // For function objects, we determine whether the function
398 // object can use the small-object optimization buffer or
399 // whether we need to allocate it on the heap.
401 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
402 functor_manager_operation_type op, function_obj_tag)
404 manager(in_buffer, out_buffer, op,
405 mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
408 // For member pointers, we use the small-object optimization buffer.
410 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
411 functor_manager_operation_type op, member_ptr_tag)
413 manager(in_buffer, out_buffer, op, mpl::true_());
417 /* Dispatch to an appropriate manager based on whether we have a
418 function pointer or a function object pointer. */
420 manage(const function_buffer& in_buffer, function_buffer& out_buffer,
421 functor_manager_operation_type op)
423 typedef typename get_function_tag<functor_type>::type tag_type;
425 case get_functor_type_tag:
426 out_buffer.type.type = &typeid(functor_type);
427 out_buffer.type.const_qualified = false;
428 out_buffer.type.volatile_qualified = false;
432 manager(in_buffer, out_buffer, op, tag_type());
438 template<typename Functor, typename Allocator>
439 struct functor_manager_a
442 typedef Functor functor_type;
446 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
447 functor_manager_operation_type op, function_ptr_tag)
449 functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
452 // Function objects that fit in the small-object buffer.
454 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
455 functor_manager_operation_type op, mpl::true_)
457 functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
460 // Function objects that require heap allocation
462 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
463 functor_manager_operation_type op, mpl::false_)
465 typedef functor_wrapper<Functor,Allocator> functor_wrapper_type;
466 typedef typename Allocator::template rebind<functor_wrapper_type>::other
467 wrapper_allocator_type;
468 typedef typename wrapper_allocator_type::pointer wrapper_allocator_pointer_type;
470 if (op == clone_functor_tag) {
472 // GCC 2.95.3 gets the CV qualifiers wrong here, so we
473 // can't do the static_cast that we should do.
474 const functor_wrapper_type* f =
475 (const functor_wrapper_type*)(in_buffer.obj_ptr);
476 wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*f));
477 wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1);
478 wrapper_allocator.construct(copy, *f);
480 // Get back to the original pointer type
481 functor_wrapper_type* new_f = static_cast<functor_wrapper_type*>(copy);
482 out_buffer.obj_ptr = new_f;
483 } else if (op == move_functor_tag) {
484 out_buffer.obj_ptr = in_buffer.obj_ptr;
485 in_buffer.obj_ptr = 0;
486 } else if (op == destroy_functor_tag) {
487 /* Cast from the void pointer to the functor_wrapper_type */
488 functor_wrapper_type* victim =
489 static_cast<functor_wrapper_type*>(in_buffer.obj_ptr);
490 wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*victim));
491 wrapper_allocator.destroy(victim);
492 wrapper_allocator.deallocate(victim,1);
493 out_buffer.obj_ptr = 0;
494 } else if (op == check_functor_type_tag) {
495 const BOOST_FUNCTION_STD_NS::type_info& check_type
496 = *out_buffer.type.type;
497 if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
498 out_buffer.obj_ptr = in_buffer.obj_ptr;
500 out_buffer.obj_ptr = 0;
501 } else /* op == get_functor_type_tag */ {
502 out_buffer.type.type = &typeid(Functor);
503 out_buffer.type.const_qualified = false;
504 out_buffer.type.volatile_qualified = false;
508 // For function objects, we determine whether the function
509 // object can use the small-object optimization buffer or
510 // whether we need to allocate it on the heap.
512 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
513 functor_manager_operation_type op, function_obj_tag)
515 manager(in_buffer, out_buffer, op,
516 mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
520 /* Dispatch to an appropriate manager based on whether we have a
521 function pointer or a function object pointer. */
523 manage(const function_buffer& in_buffer, function_buffer& out_buffer,
524 functor_manager_operation_type op)
526 typedef typename get_function_tag<functor_type>::type tag_type;
528 case get_functor_type_tag:
529 out_buffer.type.type = &typeid(functor_type);
530 out_buffer.type.const_qualified = false;
531 out_buffer.type.volatile_qualified = false;
535 manager(in_buffer, out_buffer, op, tag_type());
541 // A type that is only used for comparisons against zero
542 struct useless_clear_type {};
544 #ifdef BOOST_NO_SFINAE
545 // These routines perform comparisons between a Boost.Function
546 // object and an arbitrary function object (when the last
547 // parameter is mpl::bool_<false>) or against zero (when the
548 // last parameter is mpl::bool_<true>). They are only necessary
549 // for compilers that don't support SFINAE.
550 template<typename Function, typename Functor>
552 compare_equal(const Function& f, const Functor&, int, mpl::bool_<true>)
553 { return f.empty(); }
555 template<typename Function, typename Functor>
557 compare_not_equal(const Function& f, const Functor&, int,
559 { return !f.empty(); }
561 template<typename Function, typename Functor>
563 compare_equal(const Function& f, const Functor& g, long,
566 if (const Functor* fp = f.template target<Functor>())
567 return function_equal(*fp, g);
571 template<typename Function, typename Functor>
573 compare_equal(const Function& f, const reference_wrapper<Functor>& g,
574 int, mpl::bool_<false>)
576 if (const Functor* fp = f.template target<Functor>())
577 return fp == g.get_pointer();
581 template<typename Function, typename Functor>
583 compare_not_equal(const Function& f, const Functor& g, long,
586 if (const Functor* fp = f.template target<Functor>())
587 return !function_equal(*fp, g);
591 template<typename Function, typename Functor>
593 compare_not_equal(const Function& f,
594 const reference_wrapper<Functor>& g, int,
597 if (const Functor* fp = f.template target<Functor>())
598 return fp != g.get_pointer();
601 #endif // BOOST_NO_SFINAE
604 * Stores the "manager" portion of the vtable for a
605 * boost::function object.
609 void (*manager)(const function_buffer& in_buffer,
610 function_buffer& out_buffer,
611 functor_manager_operation_type op);
613 } // end namespace function
614 } // end namespace detail
617 * The function_base class contains the basic elements needed for the
618 * function1, function2, function3, etc. classes. It is common to all
619 * functions (and as such can be used to tell if we have one of the
620 * functionN objects).
625 function_base() : vtable(0) { }
627 /** Determine if the function is empty (i.e., has no target). */
628 bool empty() const { return !vtable; }
630 /** Retrieve the type of the stored function object, or typeid(void)
632 const BOOST_FUNCTION_STD_NS::type_info& target_type() const
634 if (!vtable) return typeid(void);
636 detail::function::function_buffer type;
637 get_vtable()->manager(functor, type, detail::function::get_functor_type_tag);
638 return *type.type.type;
641 template<typename Functor>
644 if (!vtable) return 0;
646 detail::function::function_buffer type_result;
647 type_result.type.type = &typeid(Functor);
648 type_result.type.const_qualified = is_const<Functor>::value;
649 type_result.type.volatile_qualified = is_volatile<Functor>::value;
650 get_vtable()->manager(functor, type_result,
651 detail::function::check_functor_type_tag);
652 return static_cast<Functor*>(type_result.obj_ptr);
655 template<typename Functor>
656 #if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
657 const Functor* target( Functor * = 0 ) const
659 const Functor* target() const
662 if (!vtable) return 0;
664 detail::function::function_buffer type_result;
665 type_result.type.type = &typeid(Functor);
666 type_result.type.const_qualified = true;
667 type_result.type.volatile_qualified = is_volatile<Functor>::value;
668 get_vtable()->manager(functor, type_result,
669 detail::function::check_functor_type_tag);
670 // GCC 2.95.3 gets the CV qualifiers wrong here, so we
671 // can't do the static_cast that we should do.
672 return (const Functor*)(type_result.obj_ptr);
676 bool contains(const F& f) const
678 #if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
679 if (const F* fp = this->target( (F*)0 ))
681 if (const F* fp = this->template target<F>())
684 return function_equal(*fp, f);
690 #if defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3
691 // GCC 3.3 and newer cannot copy with the global operator==, due to
692 // problems with instantiation of function return types before it
693 // has been verified that the argument types match up.
694 template<typename Functor>
695 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
696 operator==(Functor g) const
698 if (const Functor* fp = target<Functor>())
699 return function_equal(*fp, g);
703 template<typename Functor>
704 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
705 operator!=(Functor g) const
707 if (const Functor* fp = target<Functor>())
708 return !function_equal(*fp, g);
713 public: // should be protected, but GCC 2.95.3 will fail to allow access
714 detail::function::vtable_base* get_vtable() const {
715 return reinterpret_cast<detail::function::vtable_base*>(
716 reinterpret_cast<std::size_t>(vtable) & ~(std::size_t)0x01);
719 bool has_trivial_copy_and_destroy() const {
720 return reinterpret_cast<std::size_t>(vtable) & 0x01;
723 detail::function::vtable_base* vtable;
724 mutable detail::function::function_buffer functor;
728 * The bad_function_call exception class is thrown when a boost::function
731 class bad_function_call : public std::runtime_error
734 bad_function_call() : std::runtime_error("call to empty boost::function") {}
737 #ifndef BOOST_NO_SFINAE
738 inline bool operator==(const function_base& f,
739 detail::function::useless_clear_type*)
744 inline bool operator!=(const function_base& f,
745 detail::function::useless_clear_type*)
750 inline bool operator==(detail::function::useless_clear_type*,
751 const function_base& f)
756 inline bool operator!=(detail::function::useless_clear_type*,
757 const function_base& f)
763 #ifdef BOOST_NO_SFINAE
764 // Comparisons between boost::function objects and arbitrary function objects
765 template<typename Functor>
766 inline bool operator==(const function_base& f, Functor g)
768 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
769 return detail::function::compare_equal(f, g, 0, integral());
772 template<typename Functor>
773 inline bool operator==(Functor g, const function_base& f)
775 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
776 return detail::function::compare_equal(f, g, 0, integral());
779 template<typename Functor>
780 inline bool operator!=(const function_base& f, Functor g)
782 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
783 return detail::function::compare_not_equal(f, g, 0, integral());
786 template<typename Functor>
787 inline bool operator!=(Functor g, const function_base& f)
789 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
790 return detail::function::compare_not_equal(f, g, 0, integral());
794 # if !(defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3)
795 // Comparisons between boost::function objects and arbitrary function
796 // objects. GCC 3.3 and before has an obnoxious bug that prevents this
798 template<typename Functor>
799 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
800 operator==(const function_base& f, Functor g)
802 if (const Functor* fp = f.template target<Functor>())
803 return function_equal(*fp, g);
807 template<typename Functor>
808 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
809 operator==(Functor g, const function_base& f)
811 if (const Functor* fp = f.template target<Functor>())
812 return function_equal(g, *fp);
816 template<typename Functor>
817 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
818 operator!=(const function_base& f, Functor g)
820 if (const Functor* fp = f.template target<Functor>())
821 return !function_equal(*fp, g);
825 template<typename Functor>
826 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
827 operator!=(Functor g, const function_base& f)
829 if (const Functor* fp = f.template target<Functor>())
830 return !function_equal(g, *fp);
835 template<typename Functor>
836 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
837 operator==(const function_base& f, reference_wrapper<Functor> g)
839 if (const Functor* fp = f.template target<Functor>())
840 return fp == g.get_pointer();
844 template<typename Functor>
845 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
846 operator==(reference_wrapper<Functor> g, const function_base& f)
848 if (const Functor* fp = f.template target<Functor>())
849 return g.get_pointer() == fp;
853 template<typename Functor>
854 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
855 operator!=(const function_base& f, reference_wrapper<Functor> g)
857 if (const Functor* fp = f.template target<Functor>())
858 return fp != g.get_pointer();
862 template<typename Functor>
863 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
864 operator!=(reference_wrapper<Functor> g, const function_base& f)
866 if (const Functor* fp = f.template target<Functor>())
867 return g.get_pointer() != fp;
871 #endif // Compiler supporting SFINAE
875 inline bool has_empty_target(const function_base* f)
880 #if BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
881 inline bool has_empty_target(const void*)
886 inline bool has_empty_target(...)
891 } // end namespace function
892 } // end namespace detail
893 } // end namespace boost
895 #undef BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL
896 #undef BOOST_FUNCTION_COMPARE_TYPE_ID
898 #if defined(BOOST_MSVC)
899 # pragma warning( pop )
902 #endif // BOOST_FUNCTION_BASE_HEADER