diff --git a/include/boost/function/detail/prologue.hpp b/include/boost/function/detail/prologue.hpp index 1028ec8..fd51cc7 100644 --- a/include/boost/function/detail/prologue.hpp +++ b/include/boost/function/detail/prologue.hpp @@ -2,6 +2,7 @@ #define BOOST_FUNCTION_PROLOGUE_HPP # include # include +# include # include # include # include diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index ae61fda..52c07af 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -17,6 +17,7 @@ #define BOOST_FUNCTION_BASE_HEADER #include +#include #include #include #include @@ -255,52 +256,62 @@ namespace boost { } // end namespace function } // end namespace detail - /** - * The function_base class contains the basic elements needed for the - * function1, function2, function3, etc. classes. It is common to all - * functions (and as such can be used to tell if we have one of the - * functionN objects). - */ - class function_base +/** + * The function_base class contains the basic elements needed for the + * function1, function2, function3, etc. classes. It is common to all + * functions (and as such can be used to tell if we have one of the + * functionN objects). + */ +class function_base +{ +public: + function_base() : manager(0) { - public: - function_base() : manager(0) + functor.obj_ptr = 0; + } + + // Is this function empty? + bool empty() const { return !manager; } + +public: // should be protected, but GCC 2.95.3 will fail to allow access + detail::function::any_pointer (*manager)( + detail::function::any_pointer, + detail::function::functor_manager_operation_type); + detail::function::any_pointer functor; +}; + +/** + * The bad_function_call exception class is thrown when a boost::function + * object is invoked + */ +class bad_function_call : public std::runtime_error +{ +public: + bad_function_call() : std::runtime_error("call to empty boost::function") {} +}; + +/* Poison comparison between Boost.Function objects (because it is + * meaningless). The comparisons would otherwise be allowed because of the + * conversion required to allow syntax such as: + * boost::function f; + * if (f) { f(5); } + */ +void operator==(const function_base&, const function_base&); +void operator!=(const function_base&, const function_base&); + +namespace detail { + namespace function { + inline bool has_empty_target(const function_base* f) { - functor.obj_ptr = 0; + return f->empty(); } - // Is this function empty? - bool empty() const { return !manager; } - - public: // should be protected, but GCC 2.95.3 will fail to allow access - detail::function::any_pointer (*manager)( - detail::function::any_pointer, - detail::function::functor_manager_operation_type); - detail::function::any_pointer functor; - }; - - /* Poison comparison between Boost.Function objects (because it is - * meaningless). The comparisons would otherwise be allowed because of the - * conversion required to allow syntax such as: - * boost::function f; - * if (f) { f(5); } - */ - void operator==(const function_base&, const function_base&); - void operator!=(const function_base&, const function_base&); - - namespace detail { - namespace function { - inline bool has_empty_target(const function_base* f) - { - return f->empty(); - } - - inline bool has_empty_target(...) - { - return false; - } - } // end namespace function - } // end namespace detail -} + inline bool has_empty_target(...) + { + return false; + } + } // end namespace function +} // end namespace detail +} // end namespace boost #endif // BOOST_FUNCTION_BASE_HEADER diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 0630ec8..79a8a82 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -21,7 +21,6 @@ #define BOOST_FUNCTION_TEMPLATE_ARGS BOOST_PP_ENUM_PARAMS(BOOST_FUNCTION_NUM_ARGS, T) - #define BOOST_FUNCTION_PARM(J,I,D) BOOST_PP_CAT(T,I) BOOST_PP_CAT(a,I) #define BOOST_FUNCTION_PARMS BOOST_PP_ENUM(BOOST_FUNCTION_NUM_ARGS,BOOST_FUNCTION_PARM,BOOST_PP_EMPTY) @@ -247,6 +246,13 @@ namespace boost { public: BOOST_STATIC_CONSTANT(int, args = BOOST_FUNCTION_NUM_ARGS); + // add signature for boost::lambda + template + struct sig + { + typedef internal_result_type type; + }; + #if BOOST_FUNCTION_NUM_ARGS == 1 typedef T0 argument_type; #elif BOOST_FUNCTION_NUM_ARGS == 2 @@ -289,7 +295,8 @@ namespace boost { result_type operator()(BOOST_FUNCTION_PARMS) const { - assert(!this->empty()); + if (this->empty()) + boost::throw_exception(bad_function_call()); internal_result_type result = invoker(function_base::functor BOOST_FUNCTION_COMMA @@ -533,11 +540,6 @@ class function BOOST_FUNCTION_COMMA Allocator> base_type; typedef function self_type; - struct clear_type {}; - - class holder; - friend class holder; - public: typedef typename base_type::allocator_type allocator_type; @@ -548,44 +550,28 @@ public: function(const self_type& f) : base_type(static_cast(f)){} - self_type& operator=(self_type& f) + function(const base_type& f) : base_type(static_cast(f)){} + + self_type& operator=(const self_type& f) { self_type(f).swap(*this); return *this; } - inline self_type& operator=(holder h); - - self_type& operator=(clear_type*) + template + self_type& operator=(Functor f) { - this->clear(); + self_type(f).swap(*this); + return *this; + } + + self_type& operator=(const base_type& f) + { + self_type(f).swap(*this); return *this; } }; -template -class function::holder -{ -public: - template holder(F f) : func(f) {} - holder(const base_type& f) : func(f) {} - holder(const self_type& f) : func(f) {} - - self_type func; -}; - -template -function& -function::operator=(holder h) -{ - h.func.swap(*this); - return *this; -} - #undef BOOST_FUNCTION_PARTIAL_SPEC #endif // have partial specialization diff --git a/test/function_n_test.cpp b/test/function_n_test.cpp index 34817bc..3e4e92f 100644 --- a/test/function_n_test.cpp +++ b/test/function_n_test.cpp @@ -76,7 +76,7 @@ test_zero_args() // clear() method v1.clear(); - BOOST_TEST(v1.empty()); + BOOST_TEST(v1 == 0); // Assignment to an empty function v1 = three; diff --git a/test/function_test.cpp b/test/function_test.cpp index 01cb5b0..706e9cf 100644 --- a/test/function_test.cpp +++ b/test/function_test.cpp @@ -20,6 +20,7 @@ #include #include #include +#include using namespace boost; using namespace std; @@ -98,7 +99,7 @@ test_zero_args() BOOST_TEST(global_int == 5); // clear - v1 = 0; + v1.clear(); BOOST_TEST(0 == v1); // Assignment to an empty function from a free function @@ -696,6 +697,43 @@ static void test_allocator() #endif // ndef BOOST_NO_STD_ALLOCATOR } +static void test_exception() +{ + boost::function f; + try { + f(5, 4); + BOOST_TEST(false); + } + catch(boost::bad_function_call) { + // okay + } +} + +typedef boost::function< void * (void * reader) > reader_type; +typedef std::pair mapped_type; + +static void test_implicit() +{ + mapped_type m; + m = mapped_type(); +} + +static void test_call_obj(boost::function f) +{ + assert(!f.empty()); +} + +static void test_call_cref(const boost::function& f) +{ + assert(!f.empty()); +} + +static void test_call() +{ + test_call_obj(std::plus()); + test_call_cref(std::plus()); +} + int test_main(int, char* []) { test_zero_args(); @@ -705,6 +743,9 @@ int test_main(int, char* []) test_member_functions(); test_ref(); test_allocator(); + test_exception(); + test_implicit(); + test_call(); return 0; } diff --git a/test/lambda_test.cpp b/test/lambda_test.cpp new file mode 100644 index 0000000..7b9e396 --- /dev/null +++ b/test/lambda_test.cpp @@ -0,0 +1,29 @@ +#include +#include + +#include +#include +#include +#include + +using namespace std; +using namespace boost; +using namespace boost::lambda; + +static unsigned +func_impl(int arg1, bool arg2, double arg3) +{ + return abs (static_cast((arg2 ? arg1 : 2 * arg1) * arg3)); +} + +int test_main(int, char*[]) +{ + function f1 = bind(func_impl, 15, _1, _2); + function f2 = bind(f1, false, _1); + function f3 = bind(f2, 4.0); + + unsigned result = f3(); + + return 0; +} +