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 <boost/function/function_fwd.hpp>
15#include <boost/function_equal.hpp>
16#include <boost/core/typeinfo.hpp>
17#include <boost/core/ref.hpp>
18#include <boost/type_traits/has_trivial_copy.hpp>
19#include <boost/type_traits/has_trivial_destructor.hpp>
20#include <boost/type_traits/is_const.hpp>
21#include <boost/type_traits/is_integral.hpp>
22#include <boost/type_traits/is_volatile.hpp>
23#include <boost/type_traits/composite_traits.hpp>
24#include <boost/type_traits/conditional.hpp>
25#include <boost/type_traits/alignment_of.hpp>
26#include <boost/type_traits/enable_if.hpp>
27#include <boost/type_traits/integral_constant.hpp>
28#include <boost/type_traits/is_function.hpp>
29#include <boost/assert.hpp>
30#include <boost/config.hpp>
31#include <boost/config/workaround.hpp>
32#include <stdexcept>
33#include <string>
34#include <memory>
35#include <new>
36
37#if defined(BOOST_MSVC)
38# pragma warning( push )
39# pragma warning( disable : 4793 ) // complaint about native code generation
40# pragma warning( disable : 4127 ) // "conditional expression is constant"
41#endif
42
43// retained because used in a test
44#define BOOST_FUNCTION_TARGET_FIX(x)
45
46# define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \
47 typename ::boost::enable_if_< \
48 !(::boost::is_integral<Functor>::value), \
49 Type>::type
50
51namespace boost {
52 namespace detail {
53 namespace function {
54 class X;
55
56 /**
57 * A buffer used to store small function objects in
58 * boost::function. It is a union containing function pointers,
59 * object pointers, and a structure that resembles a bound
60 * member function pointer.
61 */
62 union function_buffer_members
63 {
64 // For pointers to function objects
65 typedef void* obj_ptr_t;
66 mutable obj_ptr_t obj_ptr;
67
68 // For pointers to std::type_info objects
69 struct type_t {
70 // (get_functor_type_tag, check_functor_type_tag).
71 const boost::core::typeinfo* type;
72
73 // Whether the type is const-qualified.
74 bool const_qualified;
75 // Whether the type is volatile-qualified.
76 bool volatile_qualified;
77 } type;
78
79 // For function pointers of all kinds
80 typedef void (*func_ptr_t)();
81 mutable func_ptr_t func_ptr;
82
83#if defined(BOOST_MSVC) && BOOST_MSVC >= 1929
84# pragma warning(push)
85# pragma warning(disable: 5243)
86#endif
87
88 // For bound member pointers
89 struct bound_memfunc_ptr_t {
90 void (X::*memfunc_ptr)(int);
91 void* obj_ptr;
92 } bound_memfunc_ptr;
93
94#if defined(BOOST_MSVC) && BOOST_MSVC >= 1929
95# pragma warning(pop)
96#endif
97
98 // For references to function objects. We explicitly keep
99 // track of the cv-qualifiers on the object referenced.
100 struct obj_ref_t {
101 mutable void* obj_ptr;
102 bool is_const_qualified;
103 bool is_volatile_qualified;
104 } obj_ref;
105 };
106
107 union BOOST_SYMBOL_VISIBLE function_buffer
108 {
109 // Type-specific union members
110 mutable function_buffer_members members;
111
112 // To relax aliasing constraints
113 mutable char data[sizeof(function_buffer_members)];
114 };
115
116 // The operation type to perform on the given functor/function pointer
117 enum functor_manager_operation_type {
118 clone_functor_tag,
119 move_functor_tag,
120 destroy_functor_tag,
121 check_functor_type_tag,
122 get_functor_type_tag
123 };
124
125 // Tags used to decide between different types of functions
126 struct function_ptr_tag {};
127 struct function_obj_tag {};
128 struct member_ptr_tag {};
129 struct function_obj_ref_tag {};
130
131 template<typename F>
132 class get_function_tag
133 {
134 typedef typename conditional<(is_pointer<F>::value),
135 function_ptr_tag,
136 function_obj_tag>::type ptr_or_obj_tag;
137
138 typedef typename conditional<(is_member_pointer<F>::value),
139 member_ptr_tag,
140 ptr_or_obj_tag>::type ptr_or_obj_or_mem_tag;
141
142 typedef typename conditional<(is_reference_wrapper<F>::value),
143 function_obj_ref_tag,
144 ptr_or_obj_or_mem_tag>::type or_ref_tag;
145
146 public:
147 typedef or_ref_tag type;
148 };
149
150 // The trivial manager does nothing but return the same pointer (if we
151 // are cloning) or return the null pointer (if we are deleting).
152 template<typename F>
153 struct reference_manager
154 {
155 static inline void
156 manage(const function_buffer& in_buffer, function_buffer& out_buffer,
157 functor_manager_operation_type op)
158 {
159 switch (op) {
160 case clone_functor_tag:
161 out_buffer.members.obj_ref = in_buffer.members.obj_ref;
162 return;
163
164 case move_functor_tag:
165 out_buffer.members.obj_ref = in_buffer.members.obj_ref;
166 in_buffer.members.obj_ref.obj_ptr = 0;
167 return;
168
169 case destroy_functor_tag:
170 out_buffer.members.obj_ref.obj_ptr = 0;
171 return;
172
173 case check_functor_type_tag:
174 {
175 // Check whether we have the same type. We can add
176 // cv-qualifiers, but we can't take them away.
177 if (*out_buffer.members.type.type == BOOST_CORE_TYPEID(F)
178 && (!in_buffer.members.obj_ref.is_const_qualified
179 || out_buffer.members.type.const_qualified)
180 && (!in_buffer.members.obj_ref.is_volatile_qualified
181 || out_buffer.members.type.volatile_qualified))
182 out_buffer.members.obj_ptr = in_buffer.members.obj_ref.obj_ptr;
183 else
184 out_buffer.members.obj_ptr = 0;
185 }
186 return;
187
188 case get_functor_type_tag:
189 out_buffer.members.type.type = &BOOST_CORE_TYPEID(F);
190 out_buffer.members.type.const_qualified = in_buffer.members.obj_ref.is_const_qualified;
191 out_buffer.members.type.volatile_qualified = in_buffer.members.obj_ref.is_volatile_qualified;
192 return;
193 }
194 }
195 };
196
197 /**
198 * Determine if boost::function can use the small-object
199 * optimization with the function object type F.
200 */
201 template<typename F>
202 struct function_allows_small_object_optimization
203 {
204 BOOST_STATIC_CONSTANT
205 (bool,
206 value = ((sizeof(F) <= sizeof(function_buffer) &&
207 (alignment_of<function_buffer>::value
208 % alignment_of<F>::value == 0))));
209 };
210
211 template <typename F,typename A>
212 struct functor_wrapper: public F, public A
213 {
214 functor_wrapper( F f, A a ):
215 F(f),
216 A(a)
217 {
218 }
219
220 functor_wrapper(const functor_wrapper& f) :
221 F(static_cast<const F&>(f)),
222 A(static_cast<const A&>(f))
223 {
224 }
225 };
226
227 /**
228 * The functor_manager class contains a static function "manage" which
229 * can clone or destroy the given function/function object pointer.
230 */
231 template<typename Functor>
232 struct functor_manager_common
233 {
234 typedef Functor functor_type;
235
236 // Function pointers
237 static inline void
238 manage_ptr(const function_buffer& in_buffer, function_buffer& out_buffer,
239 functor_manager_operation_type op)
240 {
241 if (op == clone_functor_tag)
242 out_buffer.members.func_ptr = in_buffer.members.func_ptr;
243 else if (op == move_functor_tag) {
244 out_buffer.members.func_ptr = in_buffer.members.func_ptr;
245 in_buffer.members.func_ptr = 0;
246 } else if (op == destroy_functor_tag)
247 out_buffer.members.func_ptr = 0;
248 else if (op == check_functor_type_tag) {
249 if (*out_buffer.members.type.type == BOOST_CORE_TYPEID(Functor))
250 out_buffer.members.obj_ptr = &in_buffer.members.func_ptr;
251 else
252 out_buffer.members.obj_ptr = 0;
253 } else /* op == get_functor_type_tag */ {
254 out_buffer.members.type.type = &BOOST_CORE_TYPEID(Functor);
255 out_buffer.members.type.const_qualified = false;
256 out_buffer.members.type.volatile_qualified = false;
257 }
258 }
259
260 // Function objects that fit in the small-object buffer.
261 static inline void
262 manage_small(const function_buffer& in_buffer, function_buffer& out_buffer,
263 functor_manager_operation_type op)
264 {
265 if (op == clone_functor_tag) {
266 const functor_type* in_functor =
267 reinterpret_cast<const functor_type*>(in_buffer.data);
268 new (reinterpret_cast<void*>(out_buffer.data)) functor_type(*in_functor);
269
270 } else if (op == move_functor_tag) {
271 functor_type* f = reinterpret_cast<functor_type*>(in_buffer.data);
272 new (reinterpret_cast<void*>(out_buffer.data)) functor_type(std::move(*f));
273 f->~Functor();
274 } else if (op == destroy_functor_tag) {
275 // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type.
276 functor_type* f = reinterpret_cast<functor_type*>(out_buffer.data);
277 (void)f; // suppress warning about the value of f not being used (MSVC)
278 f->~Functor();
279 } else if (op == check_functor_type_tag) {
280 if (*out_buffer.members.type.type == BOOST_CORE_TYPEID(Functor))
281 out_buffer.members.obj_ptr = in_buffer.data;
282 else
283 out_buffer.members.obj_ptr = 0;
284 } else /* op == get_functor_type_tag */ {
285 out_buffer.members.type.type = &BOOST_CORE_TYPEID(Functor);
286 out_buffer.members.type.const_qualified = false;
287 out_buffer.members.type.volatile_qualified = false;
288 }
289 }
290 };
291
292 template<typename Functor>
293 struct functor_manager
294 {
295 private:
296 typedef Functor functor_type;
297
298 // Function pointers
299 static inline void
300 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
301 functor_manager_operation_type op, function_ptr_tag)
302 {
303 functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
304 }
305
306 // Function objects that fit in the small-object buffer.
307 static inline void
308 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
309 functor_manager_operation_type op, true_type)
310 {
311 functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
312 }
313
314 // Function objects that require heap allocation
315 static inline void
316 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
317 functor_manager_operation_type op, false_type)
318 {
319 if (op == clone_functor_tag) {
320 // Clone the functor
321 // GCC 2.95.3 gets the CV qualifiers wrong here, so we
322 // can't do the static_cast that we should do.
323 // jewillco: Changing this to static_cast because GCC 2.95.3 is
324 // obsolete.
325 const functor_type* f =
326 static_cast<const functor_type*>(in_buffer.members.obj_ptr);
327 functor_type* new_f = new functor_type(*f);
328 out_buffer.members.obj_ptr = new_f;
329 } else if (op == move_functor_tag) {
330 out_buffer.members.obj_ptr = in_buffer.members.obj_ptr;
331 in_buffer.members.obj_ptr = 0;
332 } else if (op == destroy_functor_tag) {
333 /* Cast from the void pointer to the functor pointer type */
334 functor_type* f =
335 static_cast<functor_type*>(out_buffer.members.obj_ptr);
336 delete f;
337 out_buffer.members.obj_ptr = 0;
338 } else if (op == check_functor_type_tag) {
339 if (*out_buffer.members.type.type == BOOST_CORE_TYPEID(Functor))
340 out_buffer.members.obj_ptr = in_buffer.members.obj_ptr;
341 else
342 out_buffer.members.obj_ptr = 0;
343 } else /* op == get_functor_type_tag */ {
344 out_buffer.members.type.type = &BOOST_CORE_TYPEID(Functor);
345 out_buffer.members.type.const_qualified = false;
346 out_buffer.members.type.volatile_qualified = false;
347 }
348 }
349
350 // For function objects, we determine whether the function
351 // object can use the small-object optimization buffer or
352 // whether we need to allocate it on the heap.
353 static inline void
354 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
355 functor_manager_operation_type op, function_obj_tag)
356 {
357 manager(in_buffer, out_buffer, op,
358 integral_constant<bool, (function_allows_small_object_optimization<functor_type>::value)>());
359 }
360
361 // For member pointers, we use the small-object optimization buffer.
362 static inline void
363 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
364 functor_manager_operation_type op, member_ptr_tag)
365 {
366 manager(in_buffer, out_buffer, op, true_type());
367 }
368
369 public:
370 /* Dispatch to an appropriate manager based on whether we have a
371 function pointer or a function object pointer. */
372 static inline void
373 manage(const function_buffer& in_buffer, function_buffer& out_buffer,
374 functor_manager_operation_type op)
375 {
376 typedef typename get_function_tag<functor_type>::type tag_type;
377 if (op == get_functor_type_tag) {
378 out_buffer.members.type.type = &BOOST_CORE_TYPEID(functor_type);
379 out_buffer.members.type.const_qualified = false;
380 out_buffer.members.type.volatile_qualified = false;
381 } else {
382 manager(in_buffer, out_buffer, op, tag_type());
383 }
384 }
385 };
386
387 template<typename Functor, typename Allocator>
388 struct functor_manager_a
389 {
390 private:
391 typedef Functor functor_type;
392
393 // Function pointers
394 static inline void
395 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
396 functor_manager_operation_type op, function_ptr_tag)
397 {
398 functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
399 }
400
401 // Function objects that fit in the small-object buffer.
402 static inline void
403 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
404 functor_manager_operation_type op, true_type)
405 {
406 functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
407 }
408
409 // Function objects that require heap allocation
410 static inline void
411 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
412 functor_manager_operation_type op, false_type)
413 {
414 typedef functor_wrapper<Functor,Allocator> functor_wrapper_type;
415
416 using wrapper_allocator_type = typename std::allocator_traits<Allocator>::template rebind_alloc<functor_wrapper_type>;
417 using wrapper_allocator_pointer_type = typename std::allocator_traits<wrapper_allocator_type>::pointer;
418
419 if (op == clone_functor_tag) {
420 // Clone the functor
421 // GCC 2.95.3 gets the CV qualifiers wrong here, so we
422 // can't do the static_cast that we should do.
423 const functor_wrapper_type* f =
424 static_cast<const functor_wrapper_type*>(in_buffer.members.obj_ptr);
425 wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*f));
426 wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1);
427 std::allocator_traits<wrapper_allocator_type>::construct(wrapper_allocator, copy, *f);
428
429 // Get back to the original pointer type
430 functor_wrapper_type* new_f = static_cast<functor_wrapper_type*>(copy);
431 out_buffer.members.obj_ptr = new_f;
432 } else if (op == move_functor_tag) {
433 out_buffer.members.obj_ptr = in_buffer.members.obj_ptr;
434 in_buffer.members.obj_ptr = 0;
435 } else if (op == destroy_functor_tag) {
436 /* Cast from the void pointer to the functor_wrapper_type */
437 functor_wrapper_type* victim =
438 static_cast<functor_wrapper_type*>(in_buffer.members.obj_ptr);
439 wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*victim));
440 std::allocator_traits<wrapper_allocator_type>::destroy(wrapper_allocator, victim);
441 wrapper_allocator.deallocate(victim,1);
442 out_buffer.members.obj_ptr = 0;
443 } else if (op == check_functor_type_tag) {
444 if (*out_buffer.members.type.type == BOOST_CORE_TYPEID(Functor))
445 out_buffer.members.obj_ptr = in_buffer.members.obj_ptr;
446 else
447 out_buffer.members.obj_ptr = 0;
448 } else /* op == get_functor_type_tag */ {
449 out_buffer.members.type.type = &BOOST_CORE_TYPEID(Functor);
450 out_buffer.members.type.const_qualified = false;
451 out_buffer.members.type.volatile_qualified = false;
452 }
453 }
454
455 // For function objects, we determine whether the function
456 // object can use the small-object optimization buffer or
457 // whether we need to allocate it on the heap.
458 static inline void
459 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
460 functor_manager_operation_type op, function_obj_tag)
461 {
462 manager(in_buffer, out_buffer, op,
463 integral_constant<bool, (function_allows_small_object_optimization<functor_type>::value)>());
464 }
465
466 public:
467 /* Dispatch to an appropriate manager based on whether we have a
468 function pointer or a function object pointer. */
469 static inline void
470 manage(const function_buffer& in_buffer, function_buffer& out_buffer,
471 functor_manager_operation_type op)
472 {
473 typedef typename get_function_tag<functor_type>::type tag_type;
474 if (op == get_functor_type_tag) {
475 out_buffer.members.type.type = &BOOST_CORE_TYPEID(functor_type);
476 out_buffer.members.type.const_qualified = false;
477 out_buffer.members.type.volatile_qualified = false;
478 } else {
479 manager(in_buffer, out_buffer, op, tag_type());
480 }
481 }
482 };
483
484 // A type that is only used for comparisons against zero
485 struct useless_clear_type {};
486
487 /**
488 * Stores the "manager" portion of the vtable for a
489 * boost::function object.
490 */
491 struct vtable_base
492 {
493 void (*manager)(const function_buffer& in_buffer,
494 function_buffer& out_buffer,
495 functor_manager_operation_type op);
496 };
497 } // end namespace function
498 } // end namespace detail
499
500/**
501 * The function_base class contains the basic elements needed for the
502 * function1, function2, function3, etc. classes. It is common to all
503 * functions (and as such can be used to tell if we have one of the
504 * functionN objects).
505 */
506class function_base
507{
508public:
509 function_base() : vtable(0) { }
510
511 /** Determine if the function is empty (i.e., has no target). */
512 bool empty() const { return !vtable; }
513
514 /** Retrieve the type of the stored function object, or type_id<void>()
515 if this is empty. */
516 const boost::core::typeinfo& target_type() const
517 {
518 if (!vtable) return BOOST_CORE_TYPEID(void);
519
520 detail::function::function_buffer type;
521 get_vtable()->manager(functor, type, detail::function::get_functor_type_tag);
522 return *type.members.type.type;
523 }
524
525 template<typename Functor>
526 Functor* target()
527 {
528 if (!vtable) return 0;
529
530 detail::function::function_buffer type_result;
531 type_result.members.type.type = &BOOST_CORE_TYPEID(Functor);
532 type_result.members.type.const_qualified = is_const<Functor>::value;
533 type_result.members.type.volatile_qualified = is_volatile<Functor>::value;
534 get_vtable()->manager(functor, type_result,
535 detail::function::check_functor_type_tag);
536 return static_cast<Functor*>(type_result.members.obj_ptr);
537 }
538
539 template<typename Functor>
540 const Functor* target() const
541 {
542 if (!vtable) return 0;
543
544 detail::function::function_buffer type_result;
545 type_result.members.type.type = &BOOST_CORE_TYPEID(Functor);
546 type_result.members.type.const_qualified = true;
547 type_result.members.type.volatile_qualified = is_volatile<Functor>::value;
548 get_vtable()->manager(functor, type_result,
549 detail::function::check_functor_type_tag);
550 // GCC 2.95.3 gets the CV qualifiers wrong here, so we
551 // can't do the static_cast that we should do.
552 return static_cast<const Functor*>(type_result.members.obj_ptr);
553 }
554
555 template<typename F>
556 typename boost::enable_if_< !boost::is_function<F>::value, bool >::type
557 contains(const F& f) const
558 {
559 if (const F* fp = this->template target<F>())
560 {
561 return function_equal(*fp, f);
562 } else {
563 return false;
564 }
565 }
566
567 template<typename Fn>
568 typename boost::enable_if_< boost::is_function<Fn>::value, bool >::type
569 contains(Fn& f) const
570 {
571 typedef Fn* F;
572 if (const F* fp = this->template target<F>())
573 {
574 return function_equal(*fp, &f);
575 } else {
576 return false;
577 }
578 }
579
580public: // should be protected, but GCC 2.95.3 will fail to allow access
581 detail::function::vtable_base* get_vtable() const {
582 return reinterpret_cast<detail::function::vtable_base*>(
583 reinterpret_cast<std::size_t>(vtable) & ~static_cast<std::size_t>(0x01));
584 }
585
586 bool has_trivial_copy_and_destroy() const {
587 return reinterpret_cast<std::size_t>(vtable) & 0x01;
588 }
589
590 detail::function::vtable_base* vtable;
591 mutable detail::function::function_buffer functor;
592};
593
594#if defined(BOOST_CLANG)
595# pragma clang diagnostic push
596# pragma clang diagnostic ignored "-Wweak-vtables"
597#endif
598/**
599 * The bad_function_call exception class is thrown when a boost::function
600 * object is invoked
601 */
602class BOOST_SYMBOL_VISIBLE bad_function_call : public std::runtime_error
603{
604public:
605 bad_function_call() : std::runtime_error("call to empty boost::function") {}
606};
607#if defined(BOOST_CLANG)
608# pragma clang diagnostic pop
609#endif
610
611inline bool operator==(const function_base& f,
612 detail::function::useless_clear_type*)
613{
614 return f.empty();
615}
616
617inline bool operator!=(const function_base& f,
618 detail::function::useless_clear_type*)
619{
620 return !f.empty();
621}
622
623inline bool operator==(detail::function::useless_clear_type*,
624 const function_base& f)
625{
626 return f.empty();
627}
628
629inline bool operator!=(detail::function::useless_clear_type*,
630 const function_base& f)
631{
632 return !f.empty();
633}
634
635// Comparisons between boost::function objects and arbitrary function
636// objects.
637
638template<typename Functor>
639 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
640 operator==(const function_base& f, Functor g)
641 {
642 if (const Functor* fp = f.template target<Functor>())
643 return function_equal(*fp, g);
644 else return false;
645 }
646
647template<typename Functor>
648 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
649 operator==(Functor g, const function_base& f)
650 {
651 if (const Functor* fp = f.template target<Functor>())
652 return function_equal(g, *fp);
653 else return false;
654 }
655
656template<typename Functor>
657 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
658 operator!=(const function_base& f, Functor g)
659 {
660 if (const Functor* fp = f.template target<Functor>())
661 return !function_equal(*fp, g);
662 else return true;
663 }
664
665template<typename Functor>
666 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
667 operator!=(Functor g, const function_base& f)
668 {
669 if (const Functor* fp = f.template target<Functor>())
670 return !function_equal(g, *fp);
671 else return true;
672 }
673
674template<typename Functor>
675 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
676 operator==(const function_base& f, reference_wrapper<Functor> g)
677 {
678 if (const Functor* fp = f.template target<Functor>())
679 return fp == g.get_pointer();
680 else return false;
681 }
682
683template<typename Functor>
684 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
685 operator==(reference_wrapper<Functor> g, const function_base& f)
686 {
687 if (const Functor* fp = f.template target<Functor>())
688 return g.get_pointer() == fp;
689 else return false;
690 }
691
692template<typename Functor>
693 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
694 operator!=(const function_base& f, reference_wrapper<Functor> g)
695 {
696 if (const Functor* fp = f.template target<Functor>())
697 return fp != g.get_pointer();
698 else return true;
699 }
700
701template<typename Functor>
702 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
703 operator!=(reference_wrapper<Functor> g, const function_base& f)
704 {
705 if (const Functor* fp = f.template target<Functor>())
706 return g.get_pointer() != fp;
707 else return true;
708 }
709
710namespace detail {
711 namespace function {
712 inline bool has_empty_target(const function_base* f)
713 {
714 return f->empty();
715 }
716
717#if BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
718 inline bool has_empty_target(const void*)
719 {
720 return false;
721 }
722#else
723 inline bool has_empty_target(...)
724 {
725 return false;
726 }
727#endif
728 } // end namespace function
729} // end namespace detail
730} // end namespace boost
731
732#undef BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL
733
734#if defined(BOOST_MSVC)
735# pragma warning( pop )
736#endif
737
738#endif // BOOST_FUNCTION_BASE_HEADER
739

source code of boost/libs/function/include/boost/function/function_base.hpp