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
18 #include <boost/config.hpp>
19 #include <boost/detail/sp_typeinfo.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/ref.hpp>
29 #include <boost/mpl/if.hpp>
30 #include <boost/detail/workaround.hpp>
31 #include <boost/type_traits/alignment_of.hpp>
32 #ifndef BOOST_NO_SFINAE
33 # include "boost/utility/enable_if.hpp"
35 # include "boost/mpl/bool.hpp"
37 #include <boost/function_equal.hpp>
38 #include <boost/function/function_fwd.hpp>
40 #if defined(BOOST_MSVC)
41 # pragma warning( push )
42 # pragma warning( disable : 4793 ) // complaint about native code generation
43 # pragma warning( disable : 4127 ) // "conditional expression is constant"
46 // Define BOOST_FUNCTION_STD_NS to the namespace that contains type_info.
47 #ifdef BOOST_NO_STD_TYPEINFO
48 // Embedded VC++ does not have type_info in namespace std
49 # define BOOST_FUNCTION_STD_NS
51 # define BOOST_FUNCTION_STD_NS std
54 // Borrowed from Boost.Python library: determines the cases where we
55 // need to use std::type_info::name to compare instead of operator==.
56 #if defined( BOOST_NO_TYPEID )
57 # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y))
58 #elif defined(__GNUC__) \
60 || ( defined(__sgi) && defined(__host_mips))
62 # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) \
63 (std::strcmp((X).name(),(Y).name()) == 0)
65 # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y))
68 #if defined(__ICL) && __ICL <= 600 || defined(__MWERKS__) && __MWERKS__ < 0x2406 && !defined(BOOST_STRICT_CONFIG)
69 # define BOOST_FUNCTION_TARGET_FIX(x) x
71 # define BOOST_FUNCTION_TARGET_FIX(x)
74 # define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \
75 typename ::boost::enable_if_c< \
76 !(::boost::is_integral<Functor>::value), \
85 * A buffer used to store small function objects in
86 * boost::function. It is a union containing function pointers,
87 * object pointers, and a structure that resembles a bound
88 * member function pointer.
92 // For pointers to function objects
93 mutable void* obj_ptr;
95 // For pointers to std::type_info objects
97 // (get_functor_type_tag, check_functor_type_tag).
98 const detail::sp_typeinfo* type;
100 // Whether the type is const-qualified.
101 bool const_qualified;
102 // Whether the type is volatile-qualified.
103 bool volatile_qualified;
106 // For function pointers of all kinds
107 mutable void (*func_ptr)();
109 // For bound member pointers
110 struct bound_memfunc_ptr_t {
111 void (X::*memfunc_ptr)(int);
115 // For references to function objects. We explicitly keep
116 // track of the cv-qualifiers on the object referenced.
118 mutable void* obj_ptr;
119 bool is_const_qualified;
120 bool is_volatile_qualified;
123 // To relax aliasing constraints
128 * The unusable class is a placeholder for unused function arguments
129 * It is also completely unusable except that it constructable from
130 * anything. This helps compilers without partial specialization to
131 * handle Boost.Function objects returning void.
136 template<typename T> unusable(const T&) {}
139 /* Determine the return type. This supports compilers that do not support
140 * void returns or partial specialization by silently changing the return
141 * type to "unusable".
143 template<typename T> struct function_return_type { typedef T type; };
146 struct function_return_type<void>
148 typedef unusable type;
151 // The operation type to perform on the given functor/function pointer
152 enum functor_manager_operation_type {
156 check_functor_type_tag,
160 // Tags used to decide between different types of functions
161 struct function_ptr_tag {};
162 struct function_obj_tag {};
163 struct member_ptr_tag {};
164 struct function_obj_ref_tag {};
167 class get_function_tag
169 typedef typename mpl::if_c<(is_pointer<F>::value),
171 function_obj_tag>::type ptr_or_obj_tag;
173 typedef typename mpl::if_c<(is_member_pointer<F>::value),
175 ptr_or_obj_tag>::type ptr_or_obj_or_mem_tag;
177 typedef typename mpl::if_c<(is_reference_wrapper<F>::value),
178 function_obj_ref_tag,
179 ptr_or_obj_or_mem_tag>::type or_ref_tag;
182 typedef or_ref_tag type;
185 // The trivial manager does nothing but return the same pointer (if we
186 // are cloning) or return the null pointer (if we are deleting).
188 struct reference_manager
191 manage(const function_buffer& in_buffer, function_buffer& out_buffer,
192 functor_manager_operation_type op)
195 case clone_functor_tag:
196 out_buffer.obj_ref = in_buffer.obj_ref;
199 case move_functor_tag:
200 out_buffer.obj_ref = in_buffer.obj_ref;
201 in_buffer.obj_ref.obj_ptr = 0;
204 case destroy_functor_tag:
205 out_buffer.obj_ref.obj_ptr = 0;
208 case check_functor_type_tag:
210 const detail::sp_typeinfo& check_type
211 = *out_buffer.type.type;
213 // Check whether we have the same type. We can add
214 // cv-qualifiers, but we can't take them away.
215 if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(F))
216 && (!in_buffer.obj_ref.is_const_qualified
217 || out_buffer.type.const_qualified)
218 && (!in_buffer.obj_ref.is_volatile_qualified
219 || out_buffer.type.volatile_qualified))
220 out_buffer.obj_ptr = in_buffer.obj_ref.obj_ptr;
222 out_buffer.obj_ptr = 0;
226 case get_functor_type_tag:
227 out_buffer.type.type = &BOOST_SP_TYPEID(F);
228 out_buffer.type.const_qualified = in_buffer.obj_ref.is_const_qualified;
229 out_buffer.type.volatile_qualified = in_buffer.obj_ref.is_volatile_qualified;
236 * Determine if boost::function can use the small-object
237 * optimization with the function object type F.
240 struct function_allows_small_object_optimization
242 BOOST_STATIC_CONSTANT
244 value = ((sizeof(F) <= sizeof(function_buffer) &&
245 (alignment_of<function_buffer>::value
246 % alignment_of<F>::value == 0))));
249 template <typename F,typename A>
250 struct functor_wrapper: public F, public A
252 functor_wrapper( F f, A a ):
258 functor_wrapper(const functor_wrapper& f) :
259 F(static_cast<const F&>(f)),
260 A(static_cast<const A&>(f))
266 * The functor_manager class contains a static function "manage" which
267 * can clone or destroy the given function/function object pointer.
269 template<typename Functor>
270 struct functor_manager_common
272 typedef Functor functor_type;
276 manage_ptr(const function_buffer& in_buffer, function_buffer& out_buffer,
277 functor_manager_operation_type op)
279 if (op == clone_functor_tag)
280 out_buffer.func_ptr = in_buffer.func_ptr;
281 else if (op == move_functor_tag) {
282 out_buffer.func_ptr = in_buffer.func_ptr;
283 in_buffer.func_ptr = 0;
284 } else if (op == destroy_functor_tag)
285 out_buffer.func_ptr = 0;
286 else if (op == check_functor_type_tag) {
287 const boost::detail::sp_typeinfo& check_type
288 = *out_buffer.type.type;
289 if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(Functor)))
290 out_buffer.obj_ptr = &in_buffer.func_ptr;
292 out_buffer.obj_ptr = 0;
293 } else /* op == get_functor_type_tag */ {
294 out_buffer.type.type = &BOOST_SP_TYPEID(Functor);
295 out_buffer.type.const_qualified = false;
296 out_buffer.type.volatile_qualified = false;
300 // Function objects that fit in the small-object buffer.
302 manage_small(const function_buffer& in_buffer, function_buffer& out_buffer,
303 functor_manager_operation_type op)
305 if (op == clone_functor_tag || op == move_functor_tag) {
306 const functor_type* in_functor =
307 reinterpret_cast<const functor_type*>(&in_buffer.data);
308 new (reinterpret_cast<void*>(&out_buffer.data)) functor_type(*in_functor);
310 if (op == move_functor_tag) {
311 functor_type* f = reinterpret_cast<functor_type*>(&in_buffer.data);
312 (void)f; // suppress warning about the value of f not being used (MSVC)
315 } else if (op == destroy_functor_tag) {
316 // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type.
317 functor_type* f = reinterpret_cast<functor_type*>(&out_buffer.data);
318 (void)f; // suppress warning about the value of f not being used (MSVC)
320 } else if (op == check_functor_type_tag) {
321 const detail::sp_typeinfo& check_type
322 = *out_buffer.type.type;
323 if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(Functor)))
324 out_buffer.obj_ptr = &in_buffer.data;
326 out_buffer.obj_ptr = 0;
327 } else /* op == get_functor_type_tag */ {
328 out_buffer.type.type = &BOOST_SP_TYPEID(Functor);
329 out_buffer.type.const_qualified = false;
330 out_buffer.type.volatile_qualified = false;
335 template<typename Functor>
336 struct functor_manager
339 typedef Functor functor_type;
343 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
344 functor_manager_operation_type op, function_ptr_tag)
346 functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
349 // Function objects that fit in the small-object buffer.
351 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
352 functor_manager_operation_type op, mpl::true_)
354 functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
357 // Function objects that require heap allocation
359 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
360 functor_manager_operation_type op, mpl::false_)
362 if (op == clone_functor_tag) {
364 // GCC 2.95.3 gets the CV qualifiers wrong here, so we
365 // can't do the static_cast that we should do.
366 // jewillco: Changing this to static_cast because GCC 2.95.3 is
368 const functor_type* f =
369 static_cast<const functor_type*>(in_buffer.obj_ptr);
370 functor_type* new_f = new functor_type(*f);
371 out_buffer.obj_ptr = new_f;
372 } else if (op == move_functor_tag) {
373 out_buffer.obj_ptr = in_buffer.obj_ptr;
374 in_buffer.obj_ptr = 0;
375 } else if (op == destroy_functor_tag) {
376 /* Cast from the void pointer to the functor pointer type */
378 static_cast<functor_type*>(out_buffer.obj_ptr);
380 out_buffer.obj_ptr = 0;
381 } else if (op == check_functor_type_tag) {
382 const detail::sp_typeinfo& check_type
383 = *out_buffer.type.type;
384 if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(Functor)))
385 out_buffer.obj_ptr = in_buffer.obj_ptr;
387 out_buffer.obj_ptr = 0;
388 } else /* op == get_functor_type_tag */ {
389 out_buffer.type.type = &BOOST_SP_TYPEID(Functor);
390 out_buffer.type.const_qualified = false;
391 out_buffer.type.volatile_qualified = false;
395 // For function objects, we determine whether the function
396 // object can use the small-object optimization buffer or
397 // whether we need to allocate it on the heap.
399 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
400 functor_manager_operation_type op, function_obj_tag)
402 manager(in_buffer, out_buffer, op,
403 mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
406 // For member pointers, we use the small-object optimization buffer.
408 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
409 functor_manager_operation_type op, member_ptr_tag)
411 manager(in_buffer, out_buffer, op, mpl::true_());
415 /* Dispatch to an appropriate manager based on whether we have a
416 function pointer or a function object pointer. */
418 manage(const function_buffer& in_buffer, function_buffer& out_buffer,
419 functor_manager_operation_type op)
421 typedef typename get_function_tag<functor_type>::type tag_type;
423 case get_functor_type_tag:
424 out_buffer.type.type = &BOOST_SP_TYPEID(functor_type);
425 out_buffer.type.const_qualified = false;
426 out_buffer.type.volatile_qualified = false;
430 manager(in_buffer, out_buffer, op, tag_type());
436 template<typename Functor, typename Allocator>
437 struct functor_manager_a
440 typedef Functor functor_type;
444 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
445 functor_manager_operation_type op, function_ptr_tag)
447 functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
450 // Function objects that fit in the small-object buffer.
452 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
453 functor_manager_operation_type op, mpl::true_)
455 functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
458 // Function objects that require heap allocation
460 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
461 functor_manager_operation_type op, mpl::false_)
463 typedef functor_wrapper<Functor,Allocator> functor_wrapper_type;
464 typedef typename Allocator::template rebind<functor_wrapper_type>::other
465 wrapper_allocator_type;
466 typedef typename wrapper_allocator_type::pointer wrapper_allocator_pointer_type;
468 if (op == clone_functor_tag) {
470 // GCC 2.95.3 gets the CV qualifiers wrong here, so we
471 // can't do the static_cast that we should do.
472 const functor_wrapper_type* f =
473 static_cast<const functor_wrapper_type*>(in_buffer.obj_ptr);
474 wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*f));
475 wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1);
476 wrapper_allocator.construct(copy, *f);
478 // Get back to the original pointer type
479 functor_wrapper_type* new_f = static_cast<functor_wrapper_type*>(copy);
480 out_buffer.obj_ptr = new_f;
481 } else if (op == move_functor_tag) {
482 out_buffer.obj_ptr = in_buffer.obj_ptr;
483 in_buffer.obj_ptr = 0;
484 } else if (op == destroy_functor_tag) {
485 /* Cast from the void pointer to the functor_wrapper_type */
486 functor_wrapper_type* victim =
487 static_cast<functor_wrapper_type*>(in_buffer.obj_ptr);
488 wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*victim));
489 wrapper_allocator.destroy(victim);
490 wrapper_allocator.deallocate(victim,1);
491 out_buffer.obj_ptr = 0;
492 } else if (op == check_functor_type_tag) {
493 const detail::sp_typeinfo& check_type
494 = *out_buffer.type.type;
495 if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(Functor)))
496 out_buffer.obj_ptr = in_buffer.obj_ptr;
498 out_buffer.obj_ptr = 0;
499 } else /* op == get_functor_type_tag */ {
500 out_buffer.type.type = &BOOST_SP_TYPEID(Functor);
501 out_buffer.type.const_qualified = false;
502 out_buffer.type.volatile_qualified = false;
506 // For function objects, we determine whether the function
507 // object can use the small-object optimization buffer or
508 // whether we need to allocate it on the heap.
510 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
511 functor_manager_operation_type op, function_obj_tag)
513 manager(in_buffer, out_buffer, op,
514 mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
518 /* Dispatch to an appropriate manager based on whether we have a
519 function pointer or a function object pointer. */
521 manage(const function_buffer& in_buffer, function_buffer& out_buffer,
522 functor_manager_operation_type op)
524 typedef typename get_function_tag<functor_type>::type tag_type;
526 case get_functor_type_tag:
527 out_buffer.type.type = &BOOST_SP_TYPEID(functor_type);
528 out_buffer.type.const_qualified = false;
529 out_buffer.type.volatile_qualified = false;
533 manager(in_buffer, out_buffer, op, tag_type());
539 // A type that is only used for comparisons against zero
540 struct useless_clear_type {};
542 #ifdef BOOST_NO_SFINAE
543 // These routines perform comparisons between a Boost.Function
544 // object and an arbitrary function object (when the last
545 // parameter is mpl::bool_<false>) or against zero (when the
546 // last parameter is mpl::bool_<true>). They are only necessary
547 // for compilers that don't support SFINAE.
548 template<typename Function, typename Functor>
550 compare_equal(const Function& f, const Functor&, int, mpl::bool_<true>)
551 { return f.empty(); }
553 template<typename Function, typename Functor>
555 compare_not_equal(const Function& f, const Functor&, int,
557 { return !f.empty(); }
559 template<typename Function, typename Functor>
561 compare_equal(const Function& f, const Functor& g, long,
564 if (const Functor* fp = f.template target<Functor>())
565 return function_equal(*fp, g);
569 template<typename Function, typename Functor>
571 compare_equal(const Function& f, const reference_wrapper<Functor>& g,
572 int, mpl::bool_<false>)
574 if (const Functor* fp = f.template target<Functor>())
575 return fp == g.get_pointer();
579 template<typename Function, typename Functor>
581 compare_not_equal(const Function& f, const Functor& g, long,
584 if (const Functor* fp = f.template target<Functor>())
585 return !function_equal(*fp, g);
589 template<typename Function, typename Functor>
591 compare_not_equal(const Function& f,
592 const reference_wrapper<Functor>& g, int,
595 if (const Functor* fp = f.template target<Functor>())
596 return fp != g.get_pointer();
599 #endif // BOOST_NO_SFINAE
602 * Stores the "manager" portion of the vtable for a
603 * boost::function object.
607 void (*manager)(const function_buffer& in_buffer,
608 function_buffer& out_buffer,
609 functor_manager_operation_type op);
611 } // end namespace function
612 } // end namespace detail
615 * The function_base class contains the basic elements needed for the
616 * function1, function2, function3, etc. classes. It is common to all
617 * functions (and as such can be used to tell if we have one of the
618 * functionN objects).
623 function_base() : vtable(0) { }
625 /** Determine if the function is empty (i.e., has no target). */
626 bool empty() const { return !vtable; }
628 /** Retrieve the type of the stored function object, or BOOST_SP_TYPEID(void)
630 const detail::sp_typeinfo& target_type() const
632 if (!vtable) return BOOST_SP_TYPEID(void);
634 detail::function::function_buffer type;
635 get_vtable()->manager(functor, type, detail::function::get_functor_type_tag);
636 return *type.type.type;
639 template<typename Functor>
642 if (!vtable) return 0;
644 detail::function::function_buffer type_result;
645 type_result.type.type = &BOOST_SP_TYPEID(Functor);
646 type_result.type.const_qualified = is_const<Functor>::value;
647 type_result.type.volatile_qualified = is_volatile<Functor>::value;
648 get_vtable()->manager(functor, type_result,
649 detail::function::check_functor_type_tag);
650 return static_cast<Functor*>(type_result.obj_ptr);
653 template<typename Functor>
654 const Functor* target() const
656 if (!vtable) return 0;
658 detail::function::function_buffer type_result;
659 type_result.type.type = &BOOST_SP_TYPEID(Functor);
660 type_result.type.const_qualified = true;
661 type_result.type.volatile_qualified = is_volatile<Functor>::value;
662 get_vtable()->manager(functor, type_result,
663 detail::function::check_functor_type_tag);
664 // GCC 2.95.3 gets the CV qualifiers wrong here, so we
665 // can't do the static_cast that we should do.
666 return static_cast<const Functor*>(type_result.obj_ptr);
670 bool contains(const F& f) const
672 if (const F* fp = this->template target<F>())
674 return function_equal(*fp, f);
680 #if defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3
681 // GCC 3.3 and newer cannot copy with the global operator==, due to
682 // problems with instantiation of function return types before it
683 // has been verified that the argument types match up.
684 template<typename Functor>
685 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
686 operator==(Functor g) const
688 if (const Functor* fp = target<Functor>())
689 return function_equal(*fp, g);
693 template<typename Functor>
694 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
695 operator!=(Functor g) const
697 if (const Functor* fp = target<Functor>())
698 return !function_equal(*fp, g);
703 public: // should be protected, but GCC 2.95.3 will fail to allow access
704 detail::function::vtable_base* get_vtable() const {
705 return reinterpret_cast<detail::function::vtable_base*>(
706 reinterpret_cast<std::size_t>(vtable) & ~static_cast<std::size_t>(0x01));
709 bool has_trivial_copy_and_destroy() const {
710 return reinterpret_cast<std::size_t>(vtable) & 0x01;
713 detail::function::vtable_base* vtable;
714 mutable detail::function::function_buffer functor;
718 * The bad_function_call exception class is thrown when a boost::function
721 class bad_function_call : public std::runtime_error
724 bad_function_call() : std::runtime_error("call to empty boost::function") {}
727 #ifndef BOOST_NO_SFINAE
728 inline bool operator==(const function_base& f,
729 detail::function::useless_clear_type*)
734 inline bool operator!=(const function_base& f,
735 detail::function::useless_clear_type*)
740 inline bool operator==(detail::function::useless_clear_type*,
741 const function_base& f)
746 inline bool operator!=(detail::function::useless_clear_type*,
747 const function_base& f)
753 #ifdef BOOST_NO_SFINAE
754 // Comparisons between boost::function objects and arbitrary function objects
755 template<typename Functor>
756 inline bool operator==(const function_base& f, Functor g)
758 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
759 return detail::function::compare_equal(f, g, 0, integral());
762 template<typename Functor>
763 inline bool operator==(Functor g, const function_base& f)
765 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
766 return detail::function::compare_equal(f, g, 0, integral());
769 template<typename Functor>
770 inline bool operator!=(const function_base& f, Functor g)
772 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
773 return detail::function::compare_not_equal(f, g, 0, integral());
776 template<typename Functor>
777 inline bool operator!=(Functor g, const function_base& f)
779 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
780 return detail::function::compare_not_equal(f, g, 0, integral());
784 # if !(defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3)
785 // Comparisons between boost::function objects and arbitrary function
786 // objects. GCC 3.3 and before has an obnoxious bug that prevents this
788 template<typename Functor>
789 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
790 operator==(const function_base& f, Functor g)
792 if (const Functor* fp = f.template target<Functor>())
793 return function_equal(*fp, g);
797 template<typename Functor>
798 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
799 operator==(Functor g, const function_base& f)
801 if (const Functor* fp = f.template target<Functor>())
802 return function_equal(g, *fp);
806 template<typename Functor>
807 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
808 operator!=(const function_base& f, Functor g)
810 if (const Functor* fp = f.template target<Functor>())
811 return !function_equal(*fp, g);
815 template<typename Functor>
816 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
817 operator!=(Functor g, const function_base& f)
819 if (const Functor* fp = f.template target<Functor>())
820 return !function_equal(g, *fp);
825 template<typename Functor>
826 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
827 operator==(const function_base& f, reference_wrapper<Functor> g)
829 if (const Functor* fp = f.template target<Functor>())
830 return fp == g.get_pointer();
834 template<typename Functor>
835 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
836 operator==(reference_wrapper<Functor> g, const function_base& f)
838 if (const Functor* fp = f.template target<Functor>())
839 return g.get_pointer() == fp;
843 template<typename Functor>
844 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
845 operator!=(const function_base& f, reference_wrapper<Functor> g)
847 if (const Functor* fp = f.template target<Functor>())
848 return fp != g.get_pointer();
852 template<typename Functor>
853 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
854 operator!=(reference_wrapper<Functor> g, const function_base& f)
856 if (const Functor* fp = f.template target<Functor>())
857 return g.get_pointer() != fp;
861 #endif // Compiler supporting SFINAE
865 inline bool has_empty_target(const function_base* f)
870 #if BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
871 inline bool has_empty_target(const void*)
876 inline bool has_empty_target(...)
881 } // end namespace function
882 } // end namespace detail
883 } // end namespace boost
885 #undef BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL
886 #undef BOOST_FUNCTION_COMPARE_TYPE_ID
888 #if defined(BOOST_MSVC)
889 # pragma warning( pop )
892 #endif // BOOST_FUNCTION_BASE_HEADER