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/assert.hpp>
20 #include <boost/integer.hpp>
21 #include <boost/type_index.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 #if defined(__ICL) && __ICL <= 600 || defined(__MWERKS__) && __MWERKS__ < 0x2406 && !defined(BOOST_STRICT_CONFIG)
47 # define BOOST_FUNCTION_TARGET_FIX(x) x
49 # define BOOST_FUNCTION_TARGET_FIX(x)
52 # define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \
53 typename ::boost::enable_if_c< \
54 !(::boost::is_integral<Functor>::value), \
63 * A buffer used to store small function objects in
64 * boost::function. It is a union containing function pointers,
65 * object pointers, and a structure that resembles a bound
66 * member function pointer.
68 union function_buffer_members
70 // For pointers to function objects
71 typedef void* obj_ptr_t;
72 mutable obj_ptr_t obj_ptr;
74 // For pointers to std::type_info objects
76 // (get_functor_type_tag, check_functor_type_tag).
77 const boost::typeindex::type_info* type;
79 // Whether the type is const-qualified.
81 // Whether the type is volatile-qualified.
82 bool volatile_qualified;
85 // For function pointers of all kinds
86 typedef void (*func_ptr_t)();
87 mutable func_ptr_t func_ptr;
89 // For bound member pointers
90 struct bound_memfunc_ptr_t {
91 void (X::*memfunc_ptr)(int);
95 // For references to function objects. We explicitly keep
96 // track of the cv-qualifiers on the object referenced.
98 mutable void* obj_ptr;
99 bool is_const_qualified;
100 bool is_volatile_qualified;
104 union function_buffer
106 // Type-specific union members
107 mutable function_buffer_members members;
109 // To relax aliasing constraints
110 mutable char data[sizeof(function_buffer_members)];
114 * The unusable class is a placeholder for unused function arguments
115 * It is also completely unusable except that it constructable from
116 * anything. This helps compilers without partial specialization to
117 * handle Boost.Function objects returning void.
122 template<typename T> unusable(const T&) {}
125 /* Determine the return type. This supports compilers that do not support
126 * void returns or partial specialization by silently changing the return
127 * type to "unusable".
129 template<typename T> struct function_return_type { typedef T type; };
132 struct function_return_type<void>
134 typedef unusable type;
137 // The operation type to perform on the given functor/function pointer
138 enum functor_manager_operation_type {
142 check_functor_type_tag,
146 // Tags used to decide between different types of functions
147 struct function_ptr_tag {};
148 struct function_obj_tag {};
149 struct member_ptr_tag {};
150 struct function_obj_ref_tag {};
153 class get_function_tag
155 typedef typename mpl::if_c<(is_pointer<F>::value),
157 function_obj_tag>::type ptr_or_obj_tag;
159 typedef typename mpl::if_c<(is_member_pointer<F>::value),
161 ptr_or_obj_tag>::type ptr_or_obj_or_mem_tag;
163 typedef typename mpl::if_c<(is_reference_wrapper<F>::value),
164 function_obj_ref_tag,
165 ptr_or_obj_or_mem_tag>::type or_ref_tag;
168 typedef or_ref_tag type;
171 // The trivial manager does nothing but return the same pointer (if we
172 // are cloning) or return the null pointer (if we are deleting).
174 struct reference_manager
177 manage(const function_buffer& in_buffer, function_buffer& out_buffer,
178 functor_manager_operation_type op)
181 case clone_functor_tag:
182 out_buffer.members.obj_ref = in_buffer.members.obj_ref;
185 case move_functor_tag:
186 out_buffer.members.obj_ref = in_buffer.members.obj_ref;
187 in_buffer.members.obj_ref.obj_ptr = 0;
190 case destroy_functor_tag:
191 out_buffer.members.obj_ref.obj_ptr = 0;
194 case check_functor_type_tag:
196 // Check whether we have the same type. We can add
197 // cv-qualifiers, but we can't take them away.
198 if (*out_buffer.members.type.type == boost::typeindex::type_id<F>()
199 && (!in_buffer.members.obj_ref.is_const_qualified
200 || out_buffer.members.type.const_qualified)
201 && (!in_buffer.members.obj_ref.is_volatile_qualified
202 || out_buffer.members.type.volatile_qualified))
203 out_buffer.members.obj_ptr = in_buffer.members.obj_ref.obj_ptr;
205 out_buffer.members.obj_ptr = 0;
209 case get_functor_type_tag:
210 out_buffer.members.type.type = &boost::typeindex::type_id<F>().type_info();
211 out_buffer.members.type.const_qualified = in_buffer.members.obj_ref.is_const_qualified;
212 out_buffer.members.type.volatile_qualified = in_buffer.members.obj_ref.is_volatile_qualified;
219 * Determine if boost::function can use the small-object
220 * optimization with the function object type F.
223 struct function_allows_small_object_optimization
225 BOOST_STATIC_CONSTANT
227 value = ((sizeof(F) <= sizeof(function_buffer) &&
228 (alignment_of<function_buffer>::value
229 % alignment_of<F>::value == 0))));
232 template <typename F,typename A>
233 struct functor_wrapper: public F, public A
235 functor_wrapper( F f, A a ):
241 functor_wrapper(const functor_wrapper& f) :
242 F(static_cast<const F&>(f)),
243 A(static_cast<const A&>(f))
249 * The functor_manager class contains a static function "manage" which
250 * can clone or destroy the given function/function object pointer.
252 template<typename Functor>
253 struct functor_manager_common
255 typedef Functor functor_type;
259 manage_ptr(const function_buffer& in_buffer, function_buffer& out_buffer,
260 functor_manager_operation_type op)
262 if (op == clone_functor_tag)
263 out_buffer.members.func_ptr = in_buffer.members.func_ptr;
264 else if (op == move_functor_tag) {
265 out_buffer.members.func_ptr = in_buffer.members.func_ptr;
266 in_buffer.members.func_ptr = 0;
267 } else if (op == destroy_functor_tag)
268 out_buffer.members.func_ptr = 0;
269 else if (op == check_functor_type_tag) {
270 if (*out_buffer.members.type.type == boost::typeindex::type_id<Functor>())
271 out_buffer.members.obj_ptr = &in_buffer.members.func_ptr;
273 out_buffer.members.obj_ptr = 0;
274 } else /* op == get_functor_type_tag */ {
275 out_buffer.members.type.type = &boost::typeindex::type_id<Functor>().type_info();
276 out_buffer.members.type.const_qualified = false;
277 out_buffer.members.type.volatile_qualified = false;
281 // Function objects that fit in the small-object buffer.
283 manage_small(const function_buffer& in_buffer, function_buffer& out_buffer,
284 functor_manager_operation_type op)
286 if (op == clone_functor_tag || op == move_functor_tag) {
287 const functor_type* in_functor =
288 reinterpret_cast<const functor_type*>(in_buffer.data);
289 new (reinterpret_cast<void*>(out_buffer.data)) functor_type(*in_functor);
291 if (op == move_functor_tag) {
292 functor_type* f = reinterpret_cast<functor_type*>(in_buffer.data);
293 (void)f; // suppress warning about the value of f not being used (MSVC)
296 } else if (op == destroy_functor_tag) {
297 // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type.
298 functor_type* f = reinterpret_cast<functor_type*>(out_buffer.data);
299 (void)f; // suppress warning about the value of f not being used (MSVC)
301 } else if (op == check_functor_type_tag) {
302 if (*out_buffer.members.type.type == boost::typeindex::type_id<Functor>())
303 out_buffer.members.obj_ptr = in_buffer.data;
305 out_buffer.members.obj_ptr = 0;
306 } else /* op == get_functor_type_tag */ {
307 out_buffer.members.type.type = &boost::typeindex::type_id<Functor>().type_info();
308 out_buffer.members.type.const_qualified = false;
309 out_buffer.members.type.volatile_qualified = false;
314 template<typename Functor>
315 struct functor_manager
318 typedef Functor functor_type;
322 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
323 functor_manager_operation_type op, function_ptr_tag)
325 functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
328 // Function objects that fit in the small-object buffer.
330 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
331 functor_manager_operation_type op, mpl::true_)
333 functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
336 // Function objects that require heap allocation
338 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
339 functor_manager_operation_type op, mpl::false_)
341 if (op == clone_functor_tag) {
343 // GCC 2.95.3 gets the CV qualifiers wrong here, so we
344 // can't do the static_cast that we should do.
345 // jewillco: Changing this to static_cast because GCC 2.95.3 is
347 const functor_type* f =
348 static_cast<const functor_type*>(in_buffer.members.obj_ptr);
349 functor_type* new_f = new functor_type(*f);
350 out_buffer.members.obj_ptr = new_f;
351 } else if (op == move_functor_tag) {
352 out_buffer.members.obj_ptr = in_buffer.members.obj_ptr;
353 in_buffer.members.obj_ptr = 0;
354 } else if (op == destroy_functor_tag) {
355 /* Cast from the void pointer to the functor pointer type */
357 static_cast<functor_type*>(out_buffer.members.obj_ptr);
359 out_buffer.members.obj_ptr = 0;
360 } else if (op == check_functor_type_tag) {
361 if (*out_buffer.members.type.type == boost::typeindex::type_id<Functor>())
362 out_buffer.members.obj_ptr = in_buffer.members.obj_ptr;
364 out_buffer.members.obj_ptr = 0;
365 } else /* op == get_functor_type_tag */ {
366 out_buffer.members.type.type = &boost::typeindex::type_id<Functor>().type_info();
367 out_buffer.members.type.const_qualified = false;
368 out_buffer.members.type.volatile_qualified = false;
372 // For function objects, we determine whether the function
373 // object can use the small-object optimization buffer or
374 // whether we need to allocate it on the heap.
376 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
377 functor_manager_operation_type op, function_obj_tag)
379 manager(in_buffer, out_buffer, op,
380 mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
383 // For member pointers, we use the small-object optimization buffer.
385 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
386 functor_manager_operation_type op, member_ptr_tag)
388 manager(in_buffer, out_buffer, op, mpl::true_());
392 /* Dispatch to an appropriate manager based on whether we have a
393 function pointer or a function object pointer. */
395 manage(const function_buffer& in_buffer, function_buffer& out_buffer,
396 functor_manager_operation_type op)
398 typedef typename get_function_tag<functor_type>::type tag_type;
400 case get_functor_type_tag:
401 out_buffer.members.type.type = &boost::typeindex::type_id<functor_type>().type_info();
402 out_buffer.members.type.const_qualified = false;
403 out_buffer.members.type.volatile_qualified = false;
407 manager(in_buffer, out_buffer, op, tag_type());
413 template<typename Functor, typename Allocator>
414 struct functor_manager_a
417 typedef Functor functor_type;
421 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
422 functor_manager_operation_type op, function_ptr_tag)
424 functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
427 // Function objects that fit in the small-object buffer.
429 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
430 functor_manager_operation_type op, mpl::true_)
432 functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
435 // Function objects that require heap allocation
437 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
438 functor_manager_operation_type op, mpl::false_)
440 typedef functor_wrapper<Functor,Allocator> functor_wrapper_type;
441 #if defined(BOOST_NO_CXX11_ALLOCATOR)
442 typedef typename Allocator::template rebind<functor_wrapper_type>::other
443 wrapper_allocator_type;
444 typedef typename wrapper_allocator_type::pointer wrapper_allocator_pointer_type;
446 using wrapper_allocator_type = typename std::allocator_traits<Allocator>::template rebind_alloc<functor_wrapper_type>;
447 using wrapper_allocator_pointer_type = typename std::allocator_traits<wrapper_allocator_type>::pointer;
450 if (op == clone_functor_tag) {
452 // GCC 2.95.3 gets the CV qualifiers wrong here, so we
453 // can't do the static_cast that we should do.
454 const functor_wrapper_type* f =
455 static_cast<const functor_wrapper_type*>(in_buffer.members.obj_ptr);
456 wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*f));
457 wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1);
458 #if defined(BOOST_NO_CXX11_ALLOCATOR)
459 wrapper_allocator.construct(copy, *f);
461 std::allocator_traits<wrapper_allocator_type>::construct(wrapper_allocator, copy, *f);
464 // Get back to the original pointer type
465 functor_wrapper_type* new_f = static_cast<functor_wrapper_type*>(copy);
466 out_buffer.members.obj_ptr = new_f;
467 } else if (op == move_functor_tag) {
468 out_buffer.members.obj_ptr = in_buffer.members.obj_ptr;
469 in_buffer.members.obj_ptr = 0;
470 } else if (op == destroy_functor_tag) {
471 /* Cast from the void pointer to the functor_wrapper_type */
472 functor_wrapper_type* victim =
473 static_cast<functor_wrapper_type*>(in_buffer.members.obj_ptr);
474 wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*victim));
475 #if defined(BOOST_NO_CXX11_ALLOCATOR)
476 wrapper_allocator.destroy(victim);
478 std::allocator_traits<wrapper_allocator_type>::destroy(wrapper_allocator, victim);
480 wrapper_allocator.deallocate(victim,1);
481 out_buffer.members.obj_ptr = 0;
482 } else if (op == check_functor_type_tag) {
483 if (*out_buffer.members.type.type == boost::typeindex::type_id<Functor>())
484 out_buffer.members.obj_ptr = in_buffer.members.obj_ptr;
486 out_buffer.members.obj_ptr = 0;
487 } else /* op == get_functor_type_tag */ {
488 out_buffer.members.type.type = &boost::typeindex::type_id<Functor>().type_info();
489 out_buffer.members.type.const_qualified = false;
490 out_buffer.members.type.volatile_qualified = false;
494 // For function objects, we determine whether the function
495 // object can use the small-object optimization buffer or
496 // whether we need to allocate it on the heap.
498 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
499 functor_manager_operation_type op, function_obj_tag)
501 manager(in_buffer, out_buffer, op,
502 mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
506 /* Dispatch to an appropriate manager based on whether we have a
507 function pointer or a function object pointer. */
509 manage(const function_buffer& in_buffer, function_buffer& out_buffer,
510 functor_manager_operation_type op)
512 typedef typename get_function_tag<functor_type>::type tag_type;
514 case get_functor_type_tag:
515 out_buffer.members.type.type = &boost::typeindex::type_id<functor_type>().type_info();
516 out_buffer.members.type.const_qualified = false;
517 out_buffer.members.type.volatile_qualified = false;
521 manager(in_buffer, out_buffer, op, tag_type());
527 // A type that is only used for comparisons against zero
528 struct useless_clear_type {};
530 #ifdef BOOST_NO_SFINAE
531 // These routines perform comparisons between a Boost.Function
532 // object and an arbitrary function object (when the last
533 // parameter is mpl::bool_<false>) or against zero (when the
534 // last parameter is mpl::bool_<true>). They are only necessary
535 // for compilers that don't support SFINAE.
536 template<typename Function, typename Functor>
538 compare_equal(const Function& f, const Functor&, int, mpl::bool_<true>)
539 { return f.empty(); }
541 template<typename Function, typename Functor>
543 compare_not_equal(const Function& f, const Functor&, int,
545 { return !f.empty(); }
547 template<typename Function, typename Functor>
549 compare_equal(const Function& f, const Functor& g, long,
552 if (const Functor* fp = f.template target<Functor>())
553 return function_equal(*fp, g);
557 template<typename Function, typename Functor>
559 compare_equal(const Function& f, const reference_wrapper<Functor>& g,
560 int, mpl::bool_<false>)
562 if (const Functor* fp = f.template target<Functor>())
563 return fp == g.get_pointer();
567 template<typename Function, typename Functor>
569 compare_not_equal(const Function& f, const Functor& g, long,
572 if (const Functor* fp = f.template target<Functor>())
573 return !function_equal(*fp, g);
577 template<typename Function, typename Functor>
579 compare_not_equal(const Function& f,
580 const reference_wrapper<Functor>& g, int,
583 if (const Functor* fp = f.template target<Functor>())
584 return fp != g.get_pointer();
587 #endif // BOOST_NO_SFINAE
590 * Stores the "manager" portion of the vtable for a
591 * boost::function object.
595 void (*manager)(const function_buffer& in_buffer,
596 function_buffer& out_buffer,
597 functor_manager_operation_type op);
599 } // end namespace function
600 } // end namespace detail
603 * The function_base class contains the basic elements needed for the
604 * function1, function2, function3, etc. classes. It is common to all
605 * functions (and as such can be used to tell if we have one of the
606 * functionN objects).
611 function_base() : vtable(0) { }
613 /** Determine if the function is empty (i.e., has no target). */
614 bool empty() const { return !vtable; }
616 /** Retrieve the type of the stored function object, or type_id<void>()
618 const boost::typeindex::type_info& target_type() const
620 if (!vtable) return boost::typeindex::type_id<void>().type_info();
622 detail::function::function_buffer type;
623 get_vtable()->manager(functor, type, detail::function::get_functor_type_tag);
624 return *type.members.type.type;
627 template<typename Functor>
630 if (!vtable) return 0;
632 detail::function::function_buffer type_result;
633 type_result.members.type.type = &boost::typeindex::type_id<Functor>().type_info();
634 type_result.members.type.const_qualified = is_const<Functor>::value;
635 type_result.members.type.volatile_qualified = is_volatile<Functor>::value;
636 get_vtable()->manager(functor, type_result,
637 detail::function::check_functor_type_tag);
638 return static_cast<Functor*>(type_result.members.obj_ptr);
641 template<typename Functor>
642 const Functor* target() const
644 if (!vtable) return 0;
646 detail::function::function_buffer type_result;
647 type_result.members.type.type = &boost::typeindex::type_id<Functor>().type_info();
648 type_result.members.type.const_qualified = true;
649 type_result.members.type.volatile_qualified = is_volatile<Functor>::value;
650 get_vtable()->manager(functor, type_result,
651 detail::function::check_functor_type_tag);
652 // GCC 2.95.3 gets the CV qualifiers wrong here, so we
653 // can't do the static_cast that we should do.
654 return static_cast<const Functor*>(type_result.members.obj_ptr);
658 bool contains(const F& f) const
660 if (const F* fp = this->template target<F>())
662 return function_equal(*fp, f);
668 #if defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3
669 // GCC 3.3 and newer cannot copy with the global operator==, due to
670 // problems with instantiation of function return types before it
671 // has been verified that the argument types match up.
672 template<typename Functor>
673 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
674 operator==(Functor g) const
676 if (const Functor* fp = target<Functor>())
677 return function_equal(*fp, g);
681 template<typename Functor>
682 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
683 operator!=(Functor g) const
685 if (const Functor* fp = target<Functor>())
686 return !function_equal(*fp, g);
691 public: // should be protected, but GCC 2.95.3 will fail to allow access
692 detail::function::vtable_base* get_vtable() const {
693 return reinterpret_cast<detail::function::vtable_base*>(
694 reinterpret_cast<std::size_t>(vtable) & ~static_cast<std::size_t>(0x01));
697 bool has_trivial_copy_and_destroy() const {
698 return reinterpret_cast<std::size_t>(vtable) & 0x01;
701 detail::function::vtable_base* vtable;
702 mutable detail::function::function_buffer functor;
705 #if defined(BOOST_CLANG)
706 # pragma clang diagnostic push
707 # pragma clang diagnostic ignored "-Wweak-vtables"
710 * The bad_function_call exception class is thrown when a boost::function
713 class bad_function_call : public std::runtime_error
716 bad_function_call() : std::runtime_error("call to empty boost::function") {}
718 #if defined(BOOST_CLANG)
719 # pragma clang diagnostic pop
722 #ifndef BOOST_NO_SFINAE
723 inline bool operator==(const function_base& f,
724 detail::function::useless_clear_type*)
729 inline bool operator!=(const function_base& f,
730 detail::function::useless_clear_type*)
735 inline bool operator==(detail::function::useless_clear_type*,
736 const function_base& f)
741 inline bool operator!=(detail::function::useless_clear_type*,
742 const function_base& f)
748 #ifdef BOOST_NO_SFINAE
749 // Comparisons between boost::function objects and arbitrary function objects
750 template<typename Functor>
751 inline bool operator==(const function_base& f, Functor g)
753 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
754 return detail::function::compare_equal(f, g, 0, integral());
757 template<typename Functor>
758 inline bool operator==(Functor g, const function_base& f)
760 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
761 return detail::function::compare_equal(f, g, 0, integral());
764 template<typename Functor>
765 inline bool operator!=(const function_base& f, Functor g)
767 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
768 return detail::function::compare_not_equal(f, g, 0, integral());
771 template<typename Functor>
772 inline bool operator!=(Functor g, const function_base& f)
774 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
775 return detail::function::compare_not_equal(f, g, 0, integral());
779 # if !(defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3)
780 // Comparisons between boost::function objects and arbitrary function
781 // objects. GCC 3.3 and before has an obnoxious bug that prevents this
783 template<typename Functor>
784 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
785 operator==(const function_base& f, Functor g)
787 if (const Functor* fp = f.template target<Functor>())
788 return function_equal(*fp, g);
792 template<typename Functor>
793 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
794 operator==(Functor g, const function_base& f)
796 if (const Functor* fp = f.template target<Functor>())
797 return function_equal(g, *fp);
801 template<typename Functor>
802 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
803 operator!=(const function_base& f, Functor g)
805 if (const Functor* fp = f.template target<Functor>())
806 return !function_equal(*fp, g);
810 template<typename Functor>
811 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
812 operator!=(Functor g, const function_base& f)
814 if (const Functor* fp = f.template target<Functor>())
815 return !function_equal(g, *fp);
820 template<typename Functor>
821 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
822 operator==(const function_base& f, reference_wrapper<Functor> g)
824 if (const Functor* fp = f.template target<Functor>())
825 return fp == g.get_pointer();
829 template<typename Functor>
830 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
831 operator==(reference_wrapper<Functor> g, const function_base& f)
833 if (const Functor* fp = f.template target<Functor>())
834 return g.get_pointer() == fp;
838 template<typename Functor>
839 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
840 operator!=(const function_base& f, reference_wrapper<Functor> g)
842 if (const Functor* fp = f.template target<Functor>())
843 return fp != g.get_pointer();
847 template<typename Functor>
848 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
849 operator!=(reference_wrapper<Functor> g, const function_base& f)
851 if (const Functor* fp = f.template target<Functor>())
852 return g.get_pointer() != fp;
856 #endif // Compiler supporting SFINAE
860 inline bool has_empty_target(const function_base* f)
865 #if BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
866 inline bool has_empty_target(const void*)
871 inline bool has_empty_target(...)
876 } // end namespace function
877 } // end namespace detail
878 } // end namespace boost
880 #undef BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL
882 #if defined(BOOST_MSVC)
883 # pragma warning( pop )
886 #endif // BOOST_FUNCTION_BASE_HEADER