1 // Boost.Function library
3 // Copyright Douglas Gregor 2001-2006
4 // Copyright Emil Dotchevski 2007
5 // Use, modification and distribution is subject to the Boost Software License, Version 1.0.
6 // (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
9 // For more information, see http://www.boost.org
11 #ifndef BOOST_FUNCTION_BASE_HEADER
12 #define BOOST_FUNCTION_BASE_HEADER
19 #include <boost/config.hpp>
20 #include <boost/assert.hpp>
21 #include <boost/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"
30 # include "boost/mpl/bool.hpp"
32 #include <boost/function_equal.hpp>
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"
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
45 # define BOOST_FUNCTION_STD_NS std
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) \
52 || ( defined(__sgi) && defined(__host_mips))
54 # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) \
55 (std::strcmp((X).name(),(Y).name()) == 0)
57 # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y))
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
63 # define BOOST_FUNCTION_TARGET_FIX(x)
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 {
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
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), \
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), \
95 #if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX)
98 template<typename Signature>
101 template<typename Signature>
102 inline void swap(function<Signature>& f1,
103 function<Signature>& f2)
108 } // end namespace boost
109 #endif // have partial specialization
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.
122 union function_buffer
124 // For pointers to function objects
127 // For pointers to std::type_info objects
128 // (get_functor_type_tag, check_functor_type_tag).
129 const void* const_obj_ptr;
131 // For function pointers of all kinds
132 mutable void (*func_ptr)();
134 // For bound member pointers
135 struct bound_memfunc_ptr_t {
136 void (X::*memfunc_ptr)(int);
140 // To relax aliasing constraints
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.
153 template<typename T> unusable(const T&) {}
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".
160 template<typename T> struct function_return_type { typedef T type; };
163 struct function_return_type<void>
165 typedef unusable type;
168 // The operation type to perform on the given functor/function pointer
169 enum functor_manager_operation_type {
172 check_functor_type_tag,
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 {};
183 class get_function_tag
185 typedef typename mpl::if_c<(is_pointer<F>::value),
187 function_obj_tag>::type ptr_or_obj_tag;
189 typedef typename mpl::if_c<(is_member_pointer<F>::value),
191 ptr_or_obj_tag>::type ptr_or_obj_or_mem_tag;
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;
198 typedef or_ref_tag type;
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).
204 struct reference_manager
207 get(const function_buffer& in_buffer, function_buffer& out_buffer,
208 functor_manager_operation_type op)
211 case clone_functor_tag:
212 out_buffer.obj_ptr = in_buffer.obj_ptr;
215 case destroy_functor_tag:
216 out_buffer.obj_ptr = 0;
219 case check_functor_type_tag:
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;
229 out_buffer.obj_ptr = 0;
233 case get_functor_type_tag:
234 out_buffer.const_obj_ptr = &typeid(F);
241 * Determine if boost::function can use the small-object
242 * optimization with the function object type F.
245 struct function_allows_small_object_optimization
247 BOOST_STATIC_CONSTANT
249 value = ((sizeof(F) <= sizeof(function_buffer) &&
250 (alignment_of<function_buffer>::value
251 % alignment_of<F>::value == 0))));
254 template <typename F,typename A>
255 struct functor_wrapper: public F, public A
257 functor_wrapper( F f, A a ):
265 * The functor_manager class contains a static function "manage" which
266 * can clone or destroy the given function/function object pointer.
268 template<typename Functor>
269 struct functor_manager_common
271 typedef Functor functor_type;
275 manage_ptr(const function_buffer& in_buffer, function_buffer& out_buffer,
276 functor_manager_operation_type op)
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;
288 out_buffer.obj_ptr = 0;
292 // Function objects that fit in the small-object buffer.
294 manage_small(const function_buffer& in_buffer, function_buffer& out_buffer,
295 functor_manager_operation_type op)
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;
310 out_buffer.obj_ptr = 0;
315 template<typename Functor>
316 struct functor_manager
319 typedef Functor functor_type;
323 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
324 functor_manager_operation_type op, function_ptr_tag)
326 functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
329 // Function objects that fit in the small-object buffer.
331 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
332 functor_manager_operation_type op, mpl::true_)
334 functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
337 // Function objects that require heap allocation
339 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
340 functor_manager_operation_type op, mpl::false_)
342 if (op == clone_functor_tag) {
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 */
353 static_cast<functor_type*>(out_buffer.obj_ptr);
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;
362 out_buffer.obj_ptr = 0;
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.
370 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
371 functor_manager_operation_type op, function_obj_tag)
373 manager(in_buffer, out_buffer, op,
374 mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
378 /* Dispatch to an appropriate manager based on whether we have a
379 function pointer or a function object pointer. */
381 manage(const function_buffer& in_buffer, function_buffer& out_buffer,
382 functor_manager_operation_type op)
384 typedef typename get_function_tag<functor_type>::type tag_type;
386 case get_functor_type_tag:
387 out_buffer.const_obj_ptr = &typeid(functor_type);
391 manager(in_buffer, out_buffer, op, tag_type());
397 template<typename Functor, typename Allocator>
398 struct functor_manager_a
401 typedef Functor functor_type;
405 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
406 functor_manager_operation_type op, function_ptr_tag)
408 functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
411 // Function objects that fit in the small-object buffer.
413 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
414 functor_manager_operation_type op, mpl::true_)
416 functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
419 // Function objects that require heap allocation
421 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
422 functor_manager_operation_type op, mpl::false_)
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;
429 if (op == clone_functor_tag) {
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);
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;
456 out_buffer.obj_ptr = 0;
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.
464 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
465 functor_manager_operation_type op, function_obj_tag)
467 manager(in_buffer, out_buffer, op,
468 mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
472 /* Dispatch to an appropriate manager based on whether we have a
473 function pointer or a function object pointer. */
475 manage(const function_buffer& in_buffer, function_buffer& out_buffer,
476 functor_manager_operation_type op)
478 typedef typename get_function_tag<functor_type>::type tag_type;
480 case get_functor_type_tag:
481 out_buffer.const_obj_ptr = &typeid(functor_type);
485 manager(in_buffer, out_buffer, op, tag_type());
491 // A type that is only used for comparisons against zero
492 struct useless_clear_type {};
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>
502 compare_equal(const Function& f, const Functor&, int, mpl::bool_<true>)
503 { return f.empty(); }
505 template<typename Function, typename Functor>
507 compare_not_equal(const Function& f, const Functor&, int,
509 { return !f.empty(); }
511 template<typename Function, typename Functor>
513 compare_equal(const Function& f, const Functor& g, long,
516 if (const Functor* fp = f.template target<Functor>())
517 return function_equal(*fp, g);
521 template<typename Function, typename Functor>
523 compare_equal(const Function& f, const reference_wrapper<Functor>& g,
524 int, mpl::bool_<false>)
526 if (const Functor* fp = f.template target<Functor>())
527 return fp == g.get_pointer();
531 template<typename Function, typename Functor>
533 compare_not_equal(const Function& f, const Functor& g, long,
536 if (const Functor* fp = f.template target<Functor>())
537 return !function_equal(*fp, g);
541 template<typename Function, typename Functor>
543 compare_not_equal(const Function& f,
544 const reference_wrapper<Functor>& g, int,
547 if (const Functor* fp = f.template target<Functor>())
548 return fp != g.get_pointer();
551 #endif // BOOST_NO_SFINAE
554 * Stores the "manager" portion of the vtable for a
555 * boost::function object.
559 vtable_base() : manager(0) { }
560 void (*manager)(const function_buffer& in_buffer,
561 function_buffer& out_buffer,
562 functor_manager_operation_type op);
564 } // end namespace function
565 } // end namespace detail
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).
576 function_base() : vtable(0) { }
578 /** Determine if the function is empty (i.e., has no target). */
579 bool empty() const { return !vtable; }
581 /** Retrieve the type of the stored function object, or typeid(void)
583 const BOOST_FUNCTION_STD_NS::type_info& target_type() const
585 if (!vtable) return typeid(void);
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);
592 template<typename Functor>
595 if (!vtable) return 0;
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);
604 template<typename Functor>
605 #if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
606 const Functor* target( Functor * = 0 ) const
608 const Functor* target() const
611 if (!vtable) return 0;
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);
623 bool contains(const F& f) const
625 #if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
626 if (const F* fp = this->target( (F*)0 ))
628 if (const F* fp = this->template target<F>())
631 return function_equal(*fp, f);
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
645 if (const Functor* fp = target<Functor>())
646 return function_equal(*fp, g);
650 template<typename Functor>
651 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
652 operator!=(Functor g) const
654 if (const Functor* fp = target<Functor>())
655 return !function_equal(*fp, g);
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;
666 * The bad_function_call exception class is thrown when a boost::function
669 class bad_function_call : public std::runtime_error
672 bad_function_call() : std::runtime_error("call to empty boost::function") {}
675 #ifndef BOOST_NO_SFINAE
676 inline bool operator==(const function_base& f,
677 detail::function::useless_clear_type*)
682 inline bool operator!=(const function_base& f,
683 detail::function::useless_clear_type*)
688 inline bool operator==(detail::function::useless_clear_type*,
689 const function_base& f)
694 inline bool operator!=(detail::function::useless_clear_type*,
695 const function_base& f)
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)
706 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
707 return detail::function::compare_equal(f, g, 0, integral());
710 template<typename Functor>
711 inline bool operator==(Functor g, const function_base& f)
713 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
714 return detail::function::compare_equal(f, g, 0, integral());
717 template<typename Functor>
718 inline bool operator!=(const function_base& f, Functor g)
720 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
721 return detail::function::compare_not_equal(f, g, 0, integral());
724 template<typename Functor>
725 inline bool operator!=(Functor g, const function_base& f)
727 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
728 return detail::function::compare_not_equal(f, g, 0, integral());
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
736 template<typename Functor>
737 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
738 operator==(const function_base& f, Functor g)
740 if (const Functor* fp = f.template target<Functor>())
741 return function_equal(*fp, g);
745 template<typename Functor>
746 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
747 operator==(Functor g, const function_base& f)
749 if (const Functor* fp = f.template target<Functor>())
750 return function_equal(g, *fp);
754 template<typename Functor>
755 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
756 operator!=(const function_base& f, Functor g)
758 if (const Functor* fp = f.template target<Functor>())
759 return !function_equal(*fp, g);
763 template<typename Functor>
764 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
765 operator!=(Functor g, const function_base& f)
767 if (const Functor* fp = f.template target<Functor>())
768 return !function_equal(g, *fp);
773 template<typename Functor>
774 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
775 operator==(const function_base& f, reference_wrapper<Functor> g)
777 if (const Functor* fp = f.template target<Functor>())
778 return fp == g.get_pointer();
782 template<typename Functor>
783 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
784 operator==(reference_wrapper<Functor> g, const function_base& f)
786 if (const Functor* fp = f.template target<Functor>())
787 return g.get_pointer() == fp;
791 template<typename Functor>
792 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
793 operator!=(const function_base& f, reference_wrapper<Functor> g)
795 if (const Functor* fp = f.template target<Functor>())
796 return fp != g.get_pointer();
800 template<typename Functor>
801 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
802 operator!=(reference_wrapper<Functor> g, const function_base& f)
804 if (const Functor* fp = f.template target<Functor>())
805 return g.get_pointer() != fp;
809 #endif // Compiler supporting SFINAE
813 inline bool has_empty_target(const function_base* f)
818 #if BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
819 inline bool has_empty_target(const void*)
824 inline bool has_empty_target(...)
829 } // end namespace function
830 } // end namespace detail
831 } // end namespace boost
833 #undef BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL
834 #undef BOOST_FUNCTION_COMPARE_TYPE_ID
836 #endif // BOOST_FUNCTION_BASE_HEADER