- 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
# include <cassert>
# include <algorithm>
# include <boost/throw_exception.hpp>
# include <boost/config.hpp>
# include <boost/function/function_base.hpp>
# include <boost/mem_fn.hpp>

View File

@ -17,6 +17,7 @@
#define BOOST_FUNCTION_BASE_HEADER
#include <stdexcept>
#include <string>
#include <memory>
#include <new>
#include <boost/config.hpp>
@ -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<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?
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<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
}
inline bool has_empty_target(...)
{
return false;
}
} // end namespace function
} // end namespace detail
} // end namespace boost
#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_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<typename Args>
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_PARTIAL_SPEC, Allocator>
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<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);
return *this;
}
inline self_type& operator=(holder h);
self_type& operator=(clear_type*)
template<typename Functor>
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<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
#endif // have partial specialization

View File

@ -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;

View File

@ -20,6 +20,7 @@
#include <functional>
#include <cassert>
#include <string>
#include <utility>
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<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* [])
{
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;
}

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;
}