]> git.lyx.org Git - lyx.git/blob - boost/boost/function/function_base.hpp
update boost to version 1.36
[lyx.git] / boost / boost / function / function_base.hpp
1 // Boost.Function library
2
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)
8
9 // For more information, see http://www.boost.org
10
11 #ifndef BOOST_FUNCTION_BASE_HEADER
12 #define BOOST_FUNCTION_BASE_HEADER
13
14 #include <stdexcept>
15 #include <string>
16 #include <memory>
17 #include <new>
18 #include <typeinfo>
19 #include <boost/config.hpp>
20 #include <boost/assert.hpp>
21 #include <boost/type_traits/is_integral.hpp>
22 #include <boost/type_traits/composite_traits.hpp>
23 #include <boost/ref.hpp>
24 #include <boost/mpl/if.hpp>
25 #include <boost/detail/workaround.hpp>
26 #include <boost/type_traits/alignment_of.hpp>
27 #ifndef BOOST_NO_SFINAE
28 #  include "boost/utility/enable_if.hpp"
29 #else
30 #  include "boost/mpl/bool.hpp"
31 #endif
32 #include <boost/function_equal.hpp>
33
34 #if defined(BOOST_MSVC)
35 #   pragma warning( push )
36 #   pragma warning( disable : 4793 ) // complaint about native code generation
37 #   pragma warning( disable : 4127 ) // "conditional expression is constant"
38 #endif       
39
40 // Define BOOST_FUNCTION_STD_NS to the namespace that contains type_info.
41 #ifdef BOOST_NO_EXCEPTION_STD_NAMESPACE
42 // Embedded VC++ does not have type_info in namespace std
43 #  define BOOST_FUNCTION_STD_NS
44 #else
45 #  define BOOST_FUNCTION_STD_NS std
46 #endif
47
48 // Borrowed from Boost.Python library: determines the cases where we
49 // need to use std::type_info::name to compare instead of operator==.
50 # if (defined(__GNUC__) && __GNUC__ >= 3) \
51  || defined(_AIX) \
52  || (   defined(__sgi) && defined(__host_mips))
53 #  include <cstring>
54 #  define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) \
55      (std::strcmp((X).name(),(Y).name()) == 0)
56 # else
57 #  define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y))
58 #endif
59
60 #if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 || defined(__ICL) && __ICL <= 600 || defined(__MWERKS__) && __MWERKS__ < 0x2406 && !defined(BOOST_STRICT_CONFIG)
61 #  define BOOST_FUNCTION_TARGET_FIX(x) x
62 #else
63 #  define BOOST_FUNCTION_TARGET_FIX(x)
64 #endif // not MSVC
65
66 #if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG)
67 // Work around a compiler bug.
68 // boost::python::objects::function has to be seen by the compiler before the
69 // boost::function class template.
70 namespace boost { namespace python { namespace objects {
71   class function;
72 }}}
73 #endif
74
75 #if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)                    \
76  || defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG)                         \
77  || !(BOOST_STRICT_CONFIG || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540)
78 #  define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX
79 #endif
80
81 #if !BOOST_WORKAROUND(__BORLANDC__, < 0x600)
82 #  define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type)              \
83       typename ::boost::enable_if_c<(::boost::type_traits::ice_not<          \
84                             (::boost::is_integral<Functor>::value)>::value), \
85                            Type>::type
86 #else
87 // BCC doesn't recognize this depends on a template argument and complains
88 // about the use of 'typename'
89 #  define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type)     \
90       ::boost::enable_if_c<(::boost::type_traits::ice_not<          \
91                    (::boost::is_integral<Functor>::value)>::value), \
92                        Type>::type
93 #endif
94
95 #if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX)
96 namespace boost {
97
98 template<typename Signature>
99 class function;
100
101 template<typename Signature>
102 inline void swap(function<Signature>& f1,
103                  function<Signature>& f2)
104 {
105   f1.swap(f2);
106 }
107
108 } // end namespace boost
109 #endif // have partial specialization
110
111 namespace boost {
112   namespace detail {
113     namespace function {
114       class X;
115
116       /**
117        * A buffer used to store small function objects in
118        * boost::function. It is a union containing function pointers,
119        * object pointers, and a structure that resembles a bound
120        * member function pointer.
121        */
122       union function_buffer
123       {
124         // For pointers to function objects
125         void* obj_ptr;
126
127         // For pointers to std::type_info objects
128         // (get_functor_type_tag, check_functor_type_tag).
129         const void* const_obj_ptr;
130
131         // For function pointers of all kinds
132         mutable void (*func_ptr)();
133
134         // For bound member pointers
135         struct bound_memfunc_ptr_t {
136           void (X::*memfunc_ptr)(int);
137           void* obj_ptr;
138         } bound_memfunc_ptr;
139
140         // To relax aliasing constraints
141         mutable char data;
142       };
143
144       /**
145        * The unusable class is a placeholder for unused function arguments
146        * It is also completely unusable except that it constructable from
147        * anything. This helps compilers without partial specialization to
148        * handle Boost.Function objects returning void.
149        */
150       struct unusable
151       {
152         unusable() {}
153         template<typename T> unusable(const T&) {}
154       };
155
156       /* Determine the return type. This supports compilers that do not support
157        * void returns or partial specialization by silently changing the return
158        * type to "unusable".
159        */
160       template<typename T> struct function_return_type { typedef T type; };
161
162       template<>
163       struct function_return_type<void>
164       {
165         typedef unusable type;
166       };
167
168       // The operation type to perform on the given functor/function pointer
169       enum functor_manager_operation_type {
170         clone_functor_tag,
171         destroy_functor_tag,
172         check_functor_type_tag,
173         get_functor_type_tag
174       };
175
176       // Tags used to decide between different types of functions
177       struct function_ptr_tag {};
178       struct function_obj_tag {};
179       struct member_ptr_tag {};
180       struct function_obj_ref_tag {};
181
182       template<typename F>
183       class get_function_tag
184       {
185         typedef typename mpl::if_c<(is_pointer<F>::value),
186                                    function_ptr_tag,
187                                    function_obj_tag>::type ptr_or_obj_tag;
188
189         typedef typename mpl::if_c<(is_member_pointer<F>::value),
190                                    member_ptr_tag,
191                                    ptr_or_obj_tag>::type ptr_or_obj_or_mem_tag;
192
193         typedef typename mpl::if_c<(is_reference_wrapper<F>::value),
194                                    function_obj_ref_tag,
195                                    ptr_or_obj_or_mem_tag>::type or_ref_tag;
196
197       public:
198         typedef or_ref_tag type;
199       };
200
201       // The trivial manager does nothing but return the same pointer (if we
202       // are cloning) or return the null pointer (if we are deleting).
203       template<typename F>
204       struct reference_manager
205       {
206         static inline void
207         get(const function_buffer& in_buffer, function_buffer& out_buffer, 
208             functor_manager_operation_type op)
209         {
210           switch (op) {
211           case clone_functor_tag: 
212             out_buffer.obj_ptr = in_buffer.obj_ptr;
213             return;
214
215           case destroy_functor_tag:
216             out_buffer.obj_ptr = 0;
217             return;
218
219           case check_functor_type_tag:
220             {
221               // DPG TBD: Since we're only storing a pointer, it's
222               // possible that the user could ask for a base class or
223               // derived class. Is that okay?
224               const BOOST_FUNCTION_STD_NS::type_info& check_type = 
225                 *static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
226               if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F)))
227                 out_buffer.obj_ptr = in_buffer.obj_ptr;
228               else
229                 out_buffer.obj_ptr = 0;
230             }
231             return;
232
233           case get_functor_type_tag:
234             out_buffer.const_obj_ptr = &typeid(F);
235             return;
236           }
237         }
238       };
239
240       /**
241        * Determine if boost::function can use the small-object
242        * optimization with the function object type F.
243        */
244       template<typename F>
245       struct function_allows_small_object_optimization
246       {
247         BOOST_STATIC_CONSTANT
248           (bool, 
249            value = ((sizeof(F) <= sizeof(function_buffer) &&
250                      (alignment_of<function_buffer>::value 
251                       % alignment_of<F>::value == 0))));
252       };
253
254       template <typename F,typename A>
255       struct functor_wrapper: public F, public A
256       {
257         functor_wrapper( F f, A a ):
258           F(f),
259           A(a)
260         {
261         }
262       };
263
264       /**
265        * The functor_manager class contains a static function "manage" which
266        * can clone or destroy the given function/function object pointer.
267        */
268       template<typename Functor>
269       struct functor_manager_common
270       {
271         typedef Functor functor_type;
272
273         // Function pointers
274         static inline void
275         manage_ptr(const function_buffer& in_buffer, function_buffer& out_buffer, 
276                 functor_manager_operation_type op)
277         {
278           if (op == clone_functor_tag)
279             out_buffer.func_ptr = in_buffer.func_ptr;
280           else if (op == destroy_functor_tag)
281             out_buffer.func_ptr = 0;
282           else /* op == check_functor_type_tag */ {
283             const BOOST_FUNCTION_STD_NS::type_info& check_type = 
284               *static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
285             if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
286               out_buffer.obj_ptr = &in_buffer.func_ptr;
287             else
288               out_buffer.obj_ptr = 0;
289           }
290         }
291
292         // Function objects that fit in the small-object buffer.
293         static inline void
294         manage_small(const function_buffer& in_buffer, function_buffer& out_buffer, 
295                 functor_manager_operation_type op)
296         {
297           if (op == clone_functor_tag) {
298             const functor_type* in_functor = 
299               reinterpret_cast<const functor_type*>(&in_buffer.data);
300             new ((void*)&out_buffer.data) functor_type(*in_functor);
301           } else if (op == destroy_functor_tag) {
302             // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type.
303             reinterpret_cast<functor_type*>(&out_buffer.data)->~Functor();
304           } else /* op == check_functor_type_tag */ {
305             const BOOST_FUNCTION_STD_NS::type_info& check_type = 
306               *static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
307             if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
308               out_buffer.obj_ptr = &in_buffer.data;
309             else
310               out_buffer.obj_ptr = 0;
311           }
312         }
313       };
314
315       template<typename Functor>
316       struct functor_manager
317       {
318       private:
319         typedef Functor functor_type;
320
321         // Function pointers
322         static inline void
323         manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
324                 functor_manager_operation_type op, function_ptr_tag)
325         {
326           functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
327         }
328
329         // Function objects that fit in the small-object buffer.
330         static inline void
331         manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
332                 functor_manager_operation_type op, mpl::true_)
333         {
334           functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
335         }
336         
337         // Function objects that require heap allocation
338         static inline void
339         manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
340                 functor_manager_operation_type op, mpl::false_)
341         {
342           if (op == clone_functor_tag) {
343             // Clone the functor
344             // GCC 2.95.3 gets the CV qualifiers wrong here, so we
345             // can't do the static_cast that we should do.
346             const functor_type* f =
347               (const functor_type*)(in_buffer.obj_ptr);
348             functor_type* new_f = new functor_type(*f);
349             out_buffer.obj_ptr = new_f;
350           } else if (op == destroy_functor_tag) {
351             /* Cast from the void pointer to the functor pointer type */
352             functor_type* f =
353               static_cast<functor_type*>(out_buffer.obj_ptr);
354             delete f;
355             out_buffer.obj_ptr = 0;
356           } else /* op == check_functor_type_tag */ {
357             const BOOST_FUNCTION_STD_NS::type_info& check_type = 
358               *static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
359             if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
360               out_buffer.obj_ptr = in_buffer.obj_ptr;
361             else
362               out_buffer.obj_ptr = 0;
363           }
364         }
365
366         // For function objects, we determine whether the function
367         // object can use the small-object optimization buffer or
368         // whether we need to allocate it on the heap.
369         static inline void
370         manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
371                 functor_manager_operation_type op, function_obj_tag)
372         {
373           manager(in_buffer, out_buffer, op,
374                   mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
375         }
376
377       public:
378         /* Dispatch to an appropriate manager based on whether we have a
379            function pointer or a function object pointer. */
380         static inline void
381         manage(const function_buffer& in_buffer, function_buffer& out_buffer, 
382                functor_manager_operation_type op)
383         {
384           typedef typename get_function_tag<functor_type>::type tag_type;
385           switch (op) {
386           case get_functor_type_tag:
387             out_buffer.const_obj_ptr = &typeid(functor_type);
388             return;
389
390           default:
391             manager(in_buffer, out_buffer, op, tag_type());
392             return;
393           }
394         }
395       };
396
397       template<typename Functor, typename Allocator>
398       struct functor_manager_a
399       {
400       private:
401         typedef Functor functor_type;
402
403         // Function pointers
404         static inline void
405         manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
406                 functor_manager_operation_type op, function_ptr_tag)
407         {
408           functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
409         }
410
411         // Function objects that fit in the small-object buffer.
412         static inline void
413         manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
414                 functor_manager_operation_type op, mpl::true_)
415         {
416           functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
417         }
418         
419         // Function objects that require heap allocation
420         static inline void
421         manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
422                 functor_manager_operation_type op, mpl::false_)
423         {
424           typedef functor_wrapper<Functor,Allocator> functor_wrapper_type;
425           typedef typename Allocator::template rebind<functor_wrapper_type>::other
426             wrapper_allocator_type;
427           typedef typename wrapper_allocator_type::pointer wrapper_allocator_pointer_type;
428
429           if (op == clone_functor_tag) {
430             // Clone the functor
431             // GCC 2.95.3 gets the CV qualifiers wrong here, so we
432             // can't do the static_cast that we should do.
433             const functor_wrapper_type* f =
434               (const functor_wrapper_type*)(in_buffer.obj_ptr);
435             wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*f));
436             wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1);
437             wrapper_allocator.construct(copy, *f);
438
439             // Get back to the original pointer type
440             functor_wrapper_type* new_f = static_cast<functor_wrapper_type*>(copy);
441             out_buffer.obj_ptr = new_f;
442           } else if (op == destroy_functor_tag) {
443             /* Cast from the void pointer to the functor_wrapper_type */
444             functor_wrapper_type* victim =
445               static_cast<functor_wrapper_type*>(in_buffer.obj_ptr);
446             wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*victim));
447             wrapper_allocator.destroy(victim);
448             wrapper_allocator.deallocate(victim,1);
449             out_buffer.obj_ptr = 0;
450           } else /* op == check_functor_type_tag */ {
451             const BOOST_FUNCTION_STD_NS::type_info& check_type = 
452               *static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
453             if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
454               out_buffer.obj_ptr = in_buffer.obj_ptr;
455             else
456               out_buffer.obj_ptr = 0;
457           }
458         }
459
460         // For function objects, we determine whether the function
461         // object can use the small-object optimization buffer or
462         // whether we need to allocate it on the heap.
463         static inline void
464         manager(const function_buffer& in_buffer, function_buffer& out_buffer, 
465                 functor_manager_operation_type op, function_obj_tag)
466         {
467           manager(in_buffer, out_buffer, op,
468                   mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
469         }
470
471       public:
472         /* Dispatch to an appropriate manager based on whether we have a
473            function pointer or a function object pointer. */
474         static inline void
475         manage(const function_buffer& in_buffer, function_buffer& out_buffer, 
476                functor_manager_operation_type op)
477         {
478           typedef typename get_function_tag<functor_type>::type tag_type;
479           switch (op) {
480           case get_functor_type_tag:
481             out_buffer.const_obj_ptr = &typeid(functor_type);
482             return;
483
484           default:
485             manager(in_buffer, out_buffer, op, tag_type());
486             return;
487           }
488         }
489       };
490
491       // A type that is only used for comparisons against zero
492       struct useless_clear_type {};
493
494 #ifdef BOOST_NO_SFINAE
495       // These routines perform comparisons between a Boost.Function
496       // object and an arbitrary function object (when the last
497       // parameter is mpl::bool_<false>) or against zero (when the
498       // last parameter is mpl::bool_<true>). They are only necessary
499       // for compilers that don't support SFINAE.
500       template<typename Function, typename Functor>
501         bool
502         compare_equal(const Function& f, const Functor&, int, mpl::bool_<true>)
503         { return f.empty(); }
504
505       template<typename Function, typename Functor>
506         bool
507         compare_not_equal(const Function& f, const Functor&, int,
508                           mpl::bool_<true>)
509         { return !f.empty(); }
510
511       template<typename Function, typename Functor>
512         bool
513         compare_equal(const Function& f, const Functor& g, long,
514                       mpl::bool_<false>)
515         {
516           if (const Functor* fp = f.template target<Functor>())
517             return function_equal(*fp, g);
518           else return false;
519         }
520
521       template<typename Function, typename Functor>
522         bool
523         compare_equal(const Function& f, const reference_wrapper<Functor>& g,
524                       int, mpl::bool_<false>)
525         {
526           if (const Functor* fp = f.template target<Functor>())
527             return fp == g.get_pointer();
528           else return false;
529         }
530
531       template<typename Function, typename Functor>
532         bool
533         compare_not_equal(const Function& f, const Functor& g, long,
534                           mpl::bool_<false>)
535         {
536           if (const Functor* fp = f.template target<Functor>())
537             return !function_equal(*fp, g);
538           else return true;
539         }
540
541       template<typename Function, typename Functor>
542         bool
543         compare_not_equal(const Function& f,
544                           const reference_wrapper<Functor>& g, int,
545                           mpl::bool_<false>)
546         {
547           if (const Functor* fp = f.template target<Functor>())
548             return fp != g.get_pointer();
549           else return true;
550         }
551 #endif // BOOST_NO_SFINAE
552
553       /**
554        * Stores the "manager" portion of the vtable for a
555        * boost::function object.
556        */
557       struct vtable_base
558       {
559         vtable_base() : manager(0) { }
560         void (*manager)(const function_buffer& in_buffer, 
561                         function_buffer& out_buffer, 
562                         functor_manager_operation_type op);
563       };
564     } // end namespace function
565   } // end namespace detail
566
567 /**
568  * The function_base class contains the basic elements needed for the
569  * function1, function2, function3, etc. classes. It is common to all
570  * functions (and as such can be used to tell if we have one of the
571  * functionN objects).
572  */
573 class function_base
574 {
575 public:
576   function_base() : vtable(0) { }
577
578   /** Determine if the function is empty (i.e., has no target). */
579   bool empty() const { return !vtable; }
580
581   /** Retrieve the type of the stored function object, or typeid(void)
582       if this is empty. */
583   const BOOST_FUNCTION_STD_NS::type_info& target_type() const
584   {
585     if (!vtable) return typeid(void);
586
587     detail::function::function_buffer type;
588     vtable->manager(functor, type, detail::function::get_functor_type_tag);
589     return *static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(type.const_obj_ptr);
590   }
591
592   template<typename Functor>
593     Functor* target()
594     {
595       if (!vtable) return 0;
596
597       detail::function::function_buffer type_result;
598       type_result.const_obj_ptr = &typeid(Functor);
599       vtable->manager(functor, type_result, 
600                       detail::function::check_functor_type_tag);
601       return static_cast<Functor*>(type_result.obj_ptr);
602     }
603
604   template<typename Functor>
605 #if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
606     const Functor* target( Functor * = 0 ) const
607 #else
608     const Functor* target() const
609 #endif
610     {
611       if (!vtable) return 0;
612
613       detail::function::function_buffer type_result;
614       type_result.const_obj_ptr = &typeid(Functor);
615       vtable->manager(functor, type_result, 
616                       detail::function::check_functor_type_tag);
617       // GCC 2.95.3 gets the CV qualifiers wrong here, so we
618       // can't do the static_cast that we should do.
619       return (const Functor*)(type_result.obj_ptr);
620     }
621
622   template<typename F>
623     bool contains(const F& f) const
624     {
625 #if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
626       if (const F* fp = this->target( (F*)0 ))
627 #else
628       if (const F* fp = this->template target<F>())
629 #endif
630       {
631         return function_equal(*fp, f);
632       } else {
633         return false;
634       }
635     }
636
637 #if defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3
638   // GCC 3.3 and newer cannot copy with the global operator==, due to
639   // problems with instantiation of function return types before it
640   // has been verified that the argument types match up.
641   template<typename Functor>
642     BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
643     operator==(Functor g) const
644     {
645       if (const Functor* fp = target<Functor>())
646         return function_equal(*fp, g);
647       else return false;
648     }
649
650   template<typename Functor>
651     BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
652     operator!=(Functor g) const
653     {
654       if (const Functor* fp = target<Functor>())
655         return !function_equal(*fp, g);
656       else return true;
657     }
658 #endif
659
660 public: // should be protected, but GCC 2.95.3 will fail to allow access
661   detail::function::vtable_base* vtable;
662   mutable detail::function::function_buffer functor;
663 };
664
665 /**
666  * The bad_function_call exception class is thrown when a boost::function
667  * object is invoked
668  */
669 class bad_function_call : public std::runtime_error
670 {
671 public:
672   bad_function_call() : std::runtime_error("call to empty boost::function") {}
673 };
674
675 #ifndef BOOST_NO_SFINAE
676 inline bool operator==(const function_base& f,
677                        detail::function::useless_clear_type*)
678 {
679   return f.empty();
680 }
681
682 inline bool operator!=(const function_base& f,
683                        detail::function::useless_clear_type*)
684 {
685   return !f.empty();
686 }
687
688 inline bool operator==(detail::function::useless_clear_type*,
689                        const function_base& f)
690 {
691   return f.empty();
692 }
693
694 inline bool operator!=(detail::function::useless_clear_type*,
695                        const function_base& f)
696 {
697   return !f.empty();
698 }
699 #endif
700
701 #ifdef BOOST_NO_SFINAE
702 // Comparisons between boost::function objects and arbitrary function objects
703 template<typename Functor>
704   inline bool operator==(const function_base& f, Functor g)
705   {
706     typedef mpl::bool_<(is_integral<Functor>::value)> integral;
707     return detail::function::compare_equal(f, g, 0, integral());
708   }
709
710 template<typename Functor>
711   inline bool operator==(Functor g, const function_base& f)
712   {
713     typedef mpl::bool_<(is_integral<Functor>::value)> integral;
714     return detail::function::compare_equal(f, g, 0, integral());
715   }
716
717 template<typename Functor>
718   inline bool operator!=(const function_base& f, Functor g)
719   {
720     typedef mpl::bool_<(is_integral<Functor>::value)> integral;
721     return detail::function::compare_not_equal(f, g, 0, integral());
722   }
723
724 template<typename Functor>
725   inline bool operator!=(Functor g, const function_base& f)
726   {
727     typedef mpl::bool_<(is_integral<Functor>::value)> integral;
728     return detail::function::compare_not_equal(f, g, 0, integral());
729   }
730 #else
731
732 #  if !(defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3)
733 // Comparisons between boost::function objects and arbitrary function
734 // objects. GCC 3.3 and before has an obnoxious bug that prevents this
735 // from working.
736 template<typename Functor>
737   BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
738   operator==(const function_base& f, Functor g)
739   {
740     if (const Functor* fp = f.template target<Functor>())
741       return function_equal(*fp, g);
742     else return false;
743   }
744
745 template<typename Functor>
746   BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
747   operator==(Functor g, const function_base& f)
748   {
749     if (const Functor* fp = f.template target<Functor>())
750       return function_equal(g, *fp);
751     else return false;
752   }
753
754 template<typename Functor>
755   BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
756   operator!=(const function_base& f, Functor g)
757   {
758     if (const Functor* fp = f.template target<Functor>())
759       return !function_equal(*fp, g);
760     else return true;
761   }
762
763 template<typename Functor>
764   BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
765   operator!=(Functor g, const function_base& f)
766   {
767     if (const Functor* fp = f.template target<Functor>())
768       return !function_equal(g, *fp);
769     else return true;
770   }
771 #  endif
772
773 template<typename Functor>
774   BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
775   operator==(const function_base& f, reference_wrapper<Functor> g)
776   {
777     if (const Functor* fp = f.template target<Functor>())
778       return fp == g.get_pointer();
779     else return false;
780   }
781
782 template<typename Functor>
783   BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
784   operator==(reference_wrapper<Functor> g, const function_base& f)
785   {
786     if (const Functor* fp = f.template target<Functor>())
787       return g.get_pointer() == fp;
788     else return false;
789   }
790
791 template<typename Functor>
792   BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
793   operator!=(const function_base& f, reference_wrapper<Functor> g)
794   {
795     if (const Functor* fp = f.template target<Functor>())
796       return fp != g.get_pointer();
797     else return true;
798   }
799
800 template<typename Functor>
801   BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
802   operator!=(reference_wrapper<Functor> g, const function_base& f)
803   {
804     if (const Functor* fp = f.template target<Functor>())
805       return g.get_pointer() != fp;
806     else return true;
807   }
808
809 #endif // Compiler supporting SFINAE
810
811 namespace detail {
812   namespace function {
813     inline bool has_empty_target(const function_base* f)
814     {
815       return f->empty();
816     }
817
818 #if BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
819     inline bool has_empty_target(const void*)
820     {
821       return false;
822     }
823 #else
824     inline bool has_empty_target(...)
825     {
826       return false;
827     }
828 #endif
829   } // end namespace function
830 } // end namespace detail
831 } // end namespace boost
832
833 #undef BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL
834 #undef BOOST_FUNCTION_COMPARE_TYPE_ID
835
836 #endif // BOOST_FUNCTION_BASE_HEADER