Skip to content

Commit 17ded4b

Browse files
committed
- 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]
1 parent 9a09d9e commit 17ded4b

6 files changed

Lines changed: 147 additions & 79 deletions

File tree

include/boost/function/detail/prologue.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define BOOST_FUNCTION_PROLOGUE_HPP
33
# include <cassert>
44
# include <algorithm>
5+
# include <boost/throw_exception.hpp>
56
# include <boost/config.hpp>
67
# include <boost/function/function_base.hpp>
78
# include <boost/mem_fn.hpp>

include/boost/function/function_base.hpp

Lines changed: 54 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#define BOOST_FUNCTION_BASE_HEADER
1818

1919
#include <stdexcept>
20+
#include <string>
2021
#include <memory>
2122
#include <new>
2223
#include <boost/config.hpp>
@@ -255,52 +256,62 @@ namespace boost {
255256
} // end namespace function
256257
} // end namespace detail
257258

258-
/**
259-
* The function_base class contains the basic elements needed for the
260-
* function1, function2, function3, etc. classes. It is common to all
261-
* functions (and as such can be used to tell if we have one of the
262-
* functionN objects).
263-
*/
264-
class function_base
259+
/**
260+
* The function_base class contains the basic elements needed for the
261+
* function1, function2, function3, etc. classes. It is common to all
262+
* functions (and as such can be used to tell if we have one of the
263+
* functionN objects).
264+
*/
265+
class function_base
266+
{
267+
public:
268+
function_base() : manager(0)
265269
{
266-
public:
267-
function_base() : manager(0)
270+
functor.obj_ptr = 0;
271+
}
272+
273+
// Is this function empty?
274+
bool empty() const { return !manager; }
275+
276+
public: // should be protected, but GCC 2.95.3 will fail to allow access
277+
detail::function::any_pointer (*manager)(
278+
detail::function::any_pointer,
279+
detail::function::functor_manager_operation_type);
280+
detail::function::any_pointer functor;
281+
};
282+
283+
/**
284+
* The bad_function_call exception class is thrown when a boost::function
285+
* object is invoked
286+
*/
287+
class bad_function_call : public std::runtime_error
288+
{
289+
public:
290+
bad_function_call() : std::runtime_error("call to empty boost::function") {}
291+
};
292+
293+
/* Poison comparison between Boost.Function objects (because it is
294+
* meaningless). The comparisons would otherwise be allowed because of the
295+
* conversion required to allow syntax such as:
296+
* boost::function<int, int> f;
297+
* if (f) { f(5); }
298+
*/
299+
void operator==(const function_base&, const function_base&);
300+
void operator!=(const function_base&, const function_base&);
301+
302+
namespace detail {
303+
namespace function {
304+
inline bool has_empty_target(const function_base* f)
268305
{
269-
functor.obj_ptr = 0;
306+
return f->empty();
270307
}
271308

272-
// Is this function empty?
273-
bool empty() const { return !manager; }
274-
275-
public: // should be protected, but GCC 2.95.3 will fail to allow access
276-
detail::function::any_pointer (*manager)(
277-
detail::function::any_pointer,
278-
detail::function::functor_manager_operation_type);
279-
detail::function::any_pointer functor;
280-
};
281-
282-
/* Poison comparison between Boost.Function objects (because it is
283-
* meaningless). The comparisons would otherwise be allowed because of the
284-
* conversion required to allow syntax such as:
285-
* boost::function<int, int> f;
286-
* if (f) { f(5); }
287-
*/
288-
void operator==(const function_base&, const function_base&);
289-
void operator!=(const function_base&, const function_base&);
290-
291-
namespace detail {
292-
namespace function {
293-
inline bool has_empty_target(const function_base* f)
294-
{
295-
return f->empty();
296-
}
297-
298-
inline bool has_empty_target(...)
299-
{
300-
return false;
301-
}
302-
} // end namespace function
303-
} // end namespace detail
304-
}
309+
inline bool has_empty_target(...)
310+
{
311+
return false;
312+
}
313+
} // end namespace function
314+
} // end namespace detail
315+
} // end namespace boost
305316

306317
#endif // BOOST_FUNCTION_BASE_HEADER

include/boost/function/function_template.hpp

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
#define BOOST_FUNCTION_TEMPLATE_ARGS BOOST_PP_ENUM_PARAMS(BOOST_FUNCTION_NUM_ARGS, T)
2323

24-
2524
#define BOOST_FUNCTION_PARM(J,I,D) BOOST_PP_CAT(T,I) BOOST_PP_CAT(a,I)
2625

2726
#define BOOST_FUNCTION_PARMS BOOST_PP_ENUM(BOOST_FUNCTION_NUM_ARGS,BOOST_FUNCTION_PARM,BOOST_PP_EMPTY)
@@ -247,6 +246,13 @@ namespace boost {
247246
public:
248247
BOOST_STATIC_CONSTANT(int, args = BOOST_FUNCTION_NUM_ARGS);
249248

249+
// add signature for boost::lambda
250+
template<typename Args>
251+
struct sig
252+
{
253+
typedef internal_result_type type;
254+
};
255+
250256
#if BOOST_FUNCTION_NUM_ARGS == 1
251257
typedef T0 argument_type;
252258
#elif BOOST_FUNCTION_NUM_ARGS == 2
@@ -289,7 +295,8 @@ namespace boost {
289295

290296
result_type operator()(BOOST_FUNCTION_PARMS) const
291297
{
292-
assert(!this->empty());
298+
if (this->empty())
299+
boost::throw_exception(bad_function_call());
293300

294301
internal_result_type result = invoker(function_base::functor
295302
BOOST_FUNCTION_COMMA
@@ -533,11 +540,6 @@ class function<BOOST_FUNCTION_PARTIAL_SPEC, Allocator>
533540
BOOST_FUNCTION_COMMA Allocator> base_type;
534541
typedef function self_type;
535542

536-
struct clear_type {};
537-
538-
class holder;
539-
friend class holder;
540-
541543
public:
542544
typedef typename base_type::allocator_type allocator_type;
543545

@@ -548,44 +550,28 @@ class function<BOOST_FUNCTION_PARTIAL_SPEC, Allocator>
548550

549551
function(const self_type& f) : base_type(static_cast<const base_type&>(f)){}
550552

551-
self_type& operator=(self_type& f)
553+
function(const base_type& f) : base_type(static_cast<const base_type&>(f)){}
554+
555+
self_type& operator=(const self_type& f)
552556
{
553557
self_type(f).swap(*this);
554558
return *this;
555559
}
556560

557-
inline self_type& operator=(holder h);
558-
559-
self_type& operator=(clear_type*)
561+
template<typename Functor>
562+
self_type& operator=(Functor f)
560563
{
561-
this->clear();
564+
self_type(f).swap(*this);
562565
return *this;
563566
}
564-
};
565-
566-
template<typename R BOOST_FUNCTION_COMMA
567-
BOOST_FUNCTION_TEMPLATE_PARMS,
568-
typename Allocator>
569-
class function<BOOST_FUNCTION_PARTIAL_SPEC, Allocator>::holder
570-
{
571-
public:
572-
template<typename F> holder(F f) : func(f) {}
573-
holder(const base_type& f) : func(f) {}
574-
holder(const self_type& f) : func(f) {}
575567

576-
self_type func;
568+
self_type& operator=(const base_type& f)
569+
{
570+
self_type(f).swap(*this);
571+
return *this;
572+
}
577573
};
578574

579-
template<typename R BOOST_FUNCTION_COMMA
580-
BOOST_FUNCTION_TEMPLATE_PARMS,
581-
typename Allocator>
582-
function<BOOST_FUNCTION_PARTIAL_SPEC, Allocator>&
583-
function<BOOST_FUNCTION_PARTIAL_SPEC, Allocator>::operator=(holder h)
584-
{
585-
h.func.swap(*this);
586-
return *this;
587-
}
588-
589575
#undef BOOST_FUNCTION_PARTIAL_SPEC
590576
#endif // have partial specialization
591577

test/function_n_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ test_zero_args()
7676

7777
// clear() method
7878
v1.clear();
79-
BOOST_TEST(v1.empty());
79+
BOOST_TEST(v1 == 0);
8080

8181
// Assignment to an empty function
8282
v1 = three;

test/function_test.cpp

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <functional>
2121
#include <cassert>
2222
#include <string>
23+
#include <utility>
2324

2425
using namespace boost;
2526
using namespace std;
@@ -98,7 +99,7 @@ test_zero_args()
9899
BOOST_TEST(global_int == 5);
99100

100101
// clear
101-
v1 = 0;
102+
v1.clear();
102103
BOOST_TEST(0 == v1);
103104

104105
// Assignment to an empty function from a free function
@@ -696,6 +697,43 @@ static void test_allocator()
696697
#endif // ndef BOOST_NO_STD_ALLOCATOR
697698
}
698699

700+
static void test_exception()
701+
{
702+
boost::function<int (int, int)> f;
703+
try {
704+
f(5, 4);
705+
BOOST_TEST(false);
706+
}
707+
catch(boost::bad_function_call) {
708+
// okay
709+
}
710+
}
711+
712+
typedef boost::function< void * (void * reader) > reader_type;
713+
typedef std::pair<int, reader_type> mapped_type;
714+
715+
static void test_implicit()
716+
{
717+
mapped_type m;
718+
m = mapped_type();
719+
}
720+
721+
static void test_call_obj(boost::function<int (int, int)> f)
722+
{
723+
assert(!f.empty());
724+
}
725+
726+
static void test_call_cref(const boost::function<int (int, int)>& f)
727+
{
728+
assert(!f.empty());
729+
}
730+
731+
static void test_call()
732+
{
733+
test_call_obj(std::plus<int>());
734+
test_call_cref(std::plus<int>());
735+
}
736+
699737
int test_main(int, char* [])
700738
{
701739
test_zero_args();
@@ -705,6 +743,9 @@ int test_main(int, char* [])
705743
test_member_functions();
706744
test_ref();
707745
test_allocator();
746+
test_exception();
747+
test_implicit();
748+
test_call();
708749

709750
return 0;
710751
}

test/lambda_test.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include <iostream>
2+
#include <cstdlib>
3+
4+
#include <boost/test/test_tools.hpp>
5+
#include <boost/lambda/lambda.hpp>
6+
#include <boost/lambda/bind.hpp>
7+
#include <boost/function.hpp>
8+
9+
using namespace std;
10+
using namespace boost;
11+
using namespace boost::lambda;
12+
13+
static unsigned
14+
func_impl(int arg1, bool arg2, double arg3)
15+
{
16+
return abs (static_cast<int>((arg2 ? arg1 : 2 * arg1) * arg3));
17+
}
18+
19+
int test_main(int, char*[])
20+
{
21+
function <unsigned(bool, double)> f1 = bind(func_impl, 15, _1, _2);
22+
function <unsigned(double)> f2 = bind(f1, false, _1);
23+
function <unsigned()> f3 = bind(f2, 4.0);
24+
25+
unsigned result = f3();
26+
27+
return 0;
28+
}
29+

0 commit comments

Comments
 (0)