- Added sig member template support for Boost.Lambda, with testcase (Michael Hohmuth)

- Removed the assignment-to-zero attempt

- Added bad_function_call exception (using boost::throw_exception)


[SVN r16102]
This commit is contained in:
Douglas Gregor
2002-11-04 18:19:01 +00:00
parent 9a09d9e044
commit 17ded4b8bf
6 changed files with 148 additions and 80 deletions

View File

@ -2,6 +2,7 @@
#define BOOST_FUNCTION_PROLOGUE_HPP #define BOOST_FUNCTION_PROLOGUE_HPP
# include <cassert> # include <cassert>
# include <algorithm> # include <algorithm>
# include <boost/throw_exception.hpp>
# include <boost/config.hpp> # include <boost/config.hpp>
# include <boost/function/function_base.hpp> # include <boost/function/function_base.hpp>
# include <boost/mem_fn.hpp> # include <boost/mem_fn.hpp>

View File

@ -17,6 +17,7 @@
#define BOOST_FUNCTION_BASE_HEADER #define BOOST_FUNCTION_BASE_HEADER
#include <stdexcept> #include <stdexcept>
#include <string>
#include <memory> #include <memory>
#include <new> #include <new>
#include <boost/config.hpp> #include <boost/config.hpp>
@ -255,52 +256,62 @@ namespace boost {
} // end namespace function } // end namespace function
} // end namespace detail } // end namespace detail
/** /**
* The function_base class contains the basic elements needed for the * The function_base class contains the basic elements needed for the
* function1, function2, function3, etc. classes. It is common to all * 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 * functions (and as such can be used to tell if we have one of the
* functionN objects). * functionN objects).
*/ */
class function_base class function_base
{
public:
function_base() : manager(0)
{ {
public: functor.obj_ptr = 0;
function_base() : manager(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<int, int> 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? inline bool has_empty_target(...)
bool empty() const { return !manager; } {
return false;
public: // should be protected, but GCC 2.95.3 will fail to allow access }
detail::function::any_pointer (*manager)( } // end namespace function
detail::function::any_pointer, } // end namespace detail
detail::function::functor_manager_operation_type); } // end namespace boost
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<int, int> 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
}
#endif // BOOST_FUNCTION_BASE_HEADER #endif // BOOST_FUNCTION_BASE_HEADER

View File

@ -21,7 +21,6 @@
#define BOOST_FUNCTION_TEMPLATE_ARGS BOOST_PP_ENUM_PARAMS(BOOST_FUNCTION_NUM_ARGS, T) #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_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) #define BOOST_FUNCTION_PARMS BOOST_PP_ENUM(BOOST_FUNCTION_NUM_ARGS,BOOST_FUNCTION_PARM,BOOST_PP_EMPTY)
@ -247,6 +246,13 @@ namespace boost {
public: public:
BOOST_STATIC_CONSTANT(int, args = BOOST_FUNCTION_NUM_ARGS); BOOST_STATIC_CONSTANT(int, args = BOOST_FUNCTION_NUM_ARGS);
// add signature for boost::lambda
template<typename Args>
struct sig
{
typedef internal_result_type type;
};
#if BOOST_FUNCTION_NUM_ARGS == 1 #if BOOST_FUNCTION_NUM_ARGS == 1
typedef T0 argument_type; typedef T0 argument_type;
#elif BOOST_FUNCTION_NUM_ARGS == 2 #elif BOOST_FUNCTION_NUM_ARGS == 2
@ -289,7 +295,8 @@ namespace boost {
result_type operator()(BOOST_FUNCTION_PARMS) const 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 internal_result_type result = invoker(function_base::functor
BOOST_FUNCTION_COMMA BOOST_FUNCTION_COMMA
@ -533,11 +540,6 @@ class function<BOOST_FUNCTION_PARTIAL_SPEC, Allocator>
BOOST_FUNCTION_COMMA Allocator> base_type; BOOST_FUNCTION_COMMA Allocator> base_type;
typedef function self_type; typedef function self_type;
struct clear_type {};
class holder;
friend class holder;
public: public:
typedef typename base_type::allocator_type allocator_type; typedef typename base_type::allocator_type allocator_type;
@ -548,44 +550,28 @@ public:
function(const self_type& f) : base_type(static_cast<const base_type&>(f)){} function(const self_type& f) : base_type(static_cast<const base_type&>(f)){}
self_type& operator=(self_type& f) function(const base_type& f) : base_type(static_cast<const base_type&>(f)){}
self_type& operator=(const self_type& f)
{ {
self_type(f).swap(*this); self_type(f).swap(*this);
return *this; return *this;
} }
inline self_type& operator=(holder h); template<typename Functor>
self_type& operator=(Functor f)
self_type& operator=(clear_type*)
{ {
this->clear(); self_type(f).swap(*this);
return *this;
}
self_type& operator=(const base_type& f)
{
self_type(f).swap(*this);
return *this; return *this;
} }
}; };
template<typename R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_PARMS,
typename Allocator>
class function<BOOST_FUNCTION_PARTIAL_SPEC, Allocator>::holder
{
public:
template<typename F> holder(F f) : func(f) {}
holder(const base_type& f) : func(f) {}
holder(const self_type& f) : func(f) {}
self_type func;
};
template<typename R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_PARMS,
typename Allocator>
function<BOOST_FUNCTION_PARTIAL_SPEC, Allocator>&
function<BOOST_FUNCTION_PARTIAL_SPEC, Allocator>::operator=(holder h)
{
h.func.swap(*this);
return *this;
}
#undef BOOST_FUNCTION_PARTIAL_SPEC #undef BOOST_FUNCTION_PARTIAL_SPEC
#endif // have partial specialization #endif // have partial specialization

View File

@ -76,7 +76,7 @@ test_zero_args()
// clear() method // clear() method
v1.clear(); v1.clear();
BOOST_TEST(v1.empty()); BOOST_TEST(v1 == 0);
// Assignment to an empty function // Assignment to an empty function
v1 = three; v1 = three;

View File

@ -20,6 +20,7 @@
#include <functional> #include <functional>
#include <cassert> #include <cassert>
#include <string> #include <string>
#include <utility>
using namespace boost; using namespace boost;
using namespace std; using namespace std;
@ -98,7 +99,7 @@ test_zero_args()
BOOST_TEST(global_int == 5); BOOST_TEST(global_int == 5);
// clear // clear
v1 = 0; v1.clear();
BOOST_TEST(0 == v1); BOOST_TEST(0 == v1);
// Assignment to an empty function from a free function // Assignment to an empty function from a free function
@ -696,6 +697,43 @@ static void test_allocator()
#endif // ndef BOOST_NO_STD_ALLOCATOR #endif // ndef BOOST_NO_STD_ALLOCATOR
} }
static void test_exception()
{
boost::function<int (int, int)> 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<int, reader_type> mapped_type;
static void test_implicit()
{
mapped_type m;
m = mapped_type();
}
static void test_call_obj(boost::function<int (int, int)> f)
{
assert(!f.empty());
}
static void test_call_cref(const boost::function<int (int, int)>& f)
{
assert(!f.empty());
}
static void test_call()
{
test_call_obj(std::plus<int>());
test_call_cref(std::plus<int>());
}
int test_main(int, char* []) int test_main(int, char* [])
{ {
test_zero_args(); test_zero_args();
@ -705,6 +743,9 @@ int test_main(int, char* [])
test_member_functions(); test_member_functions();
test_ref(); test_ref();
test_allocator(); test_allocator();
test_exception();
test_implicit();
test_call();
return 0; return 0;
} }

29
test/lambda_test.cpp Normal file
View File

@ -0,0 +1,29 @@
#include <iostream>
#include <cstdlib>
#include <boost/test/test_tools.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/function.hpp>
using namespace std;
using namespace boost;
using namespace boost::lambda;
static unsigned
func_impl(int arg1, bool arg2, double arg3)
{
return abs (static_cast<int>((arg2 ? arg1 : 2 * arg1) * arg3));
}
int test_main(int, char*[])
{
function <unsigned(bool, double)> f1 = bind(func_impl, 15, _1, _2);
function <unsigned(double)> f2 = bind(f1, false, _1);
function <unsigned()> f3 = bind(f2, 4.0);
unsigned result = f3();
return 0;
}