mirror of
https://github.com/boostorg/lambda.git
synced 2026-01-21 04:52:25 +00:00
a lot of changes:
support for FC++ style sig templates for return type deduction support for currying lambda functors proper protect support if lambda functors are bound, return type deduction works [SVN r12273]
This commit is contained in:
@@ -22,9 +22,8 @@ namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
|
||||
template<int Arity, class Act> struct action;
|
||||
|
||||
|
||||
template<int Arity, class Act> struct action;
|
||||
|
||||
// these need to be defined here, since the corresponding lambda
|
||||
// functions are members of lambda_functor classes
|
||||
@@ -172,6 +171,27 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// actions, for which the existence of protect is checked in return type
|
||||
// deduction.
|
||||
class protectable {};
|
||||
|
||||
namespace detail {
|
||||
template<class T> struct is_protectable_action {
|
||||
BOOST_STATIC_CONSTANT(bool, value = (boost::is_base_and_derived<protectable, T>::value));
|
||||
};
|
||||
|
||||
template<> struct is_protectable_action<other_action<assignment_action> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template<> struct is_protectable_action<other_action<comma_action> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
|
||||
} // end detail
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace lambda
|
||||
} // namespace boost
|
||||
|
||||
|
||||
@@ -45,6 +45,12 @@ template <class T> struct dig_arity;
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
template <int Arity, int Step> struct reduce_arity
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(int, value = Arity >> Step);
|
||||
};
|
||||
|
||||
// The implementation template, do not instantiate this directly
|
||||
template <class Arg> struct dig_arity_ {
|
||||
static const int value = NONE;
|
||||
|
||||
@@ -513,28 +513,71 @@ struct function_adaptor<Result (*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg
|
||||
// we want to instantiate function adaptor from different places.
|
||||
// sometimes Func does not have the result_type defined. It is therefore
|
||||
// queried in a separate subclass.
|
||||
// Thus the super class can
|
||||
// Thus the super class can be
|
||||
// instantiated even with a Func that does no have result_type
|
||||
|
||||
|
||||
struct has_sig {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class T> struct get_result_type {
|
||||
typedef typename T::result_type type;
|
||||
template <class F> struct get_result_type {
|
||||
typedef typename F::result_type type;
|
||||
};
|
||||
|
||||
template <class Args> class get_sig_result_type {
|
||||
typedef typename Args::head_type Func;
|
||||
typedef typename detail::remove_reference_and_cv<Func>::type plainF;
|
||||
public:
|
||||
// To sig we pass a cons list, where the head is the function object type
|
||||
// itself (potentially cv-qualified, but not a reference type)
|
||||
// and the tail contains the types of the actual arguments to be passed
|
||||
// to the function object. The arguments are reference types
|
||||
typedef typename plainF::template sig<Args>::type type;
|
||||
};
|
||||
|
||||
|
||||
// check for a member typedef return_type or an member class template sig
|
||||
template <class Args> class get_functor_result_type {
|
||||
typedef typename Args::head_type Func;
|
||||
typedef typename boost::remove_cv<Func>::type plain_F;
|
||||
public:
|
||||
// if the function object inherits from has_sig, we check for sig
|
||||
// otherwise for result_type typedef
|
||||
typedef
|
||||
detail::IF_type<
|
||||
boost::is_base_and_derived<has_sig, plain_F>::value,
|
||||
detail::get_sig_result_type<Args>,
|
||||
detail::get_result_type<Func>
|
||||
>::type type;
|
||||
};
|
||||
|
||||
|
||||
} // end detail
|
||||
|
||||
template <class Func> class function_adaptor_sub :
|
||||
public function_adaptor<Func> {
|
||||
|
||||
typedef typename function_adaptor<Func>::type type1;
|
||||
template <class Args>
|
||||
class function_adaptor_with_actuals //: public
|
||||
// function_adaptor<typename detail::remove_reference_and_cv<
|
||||
// typename Args::head_type
|
||||
// >::type>
|
||||
{
|
||||
typedef typename Args::head_type Func;
|
||||
typedef typename boost::remove_reference<Func>::type non_ref_Func;
|
||||
typedef typename boost::remove_cv<non_ref_Func>::type plain_Func;
|
||||
typedef typename function_adaptor<plain_Func>::type type1;
|
||||
|
||||
public:
|
||||
|
||||
typedef typename
|
||||
detail::IF_type<
|
||||
boost::is_same<type1, detail::unspecified>::value,
|
||||
detail::get_result_type<Func>, // it's ok to try this
|
||||
function_adaptor<Func>
|
||||
detail::get_functor_result_type<
|
||||
boost::tuples::cons<non_ref_Func, typename Args::tail_type>
|
||||
>, // it's ok to try this (an arbitrary func. object)
|
||||
function_adaptor<plain_Func>
|
||||
// Here we know Func's ret type
|
||||
// (func is a member function or function pointer/reference)
|
||||
>::type type;
|
||||
|
||||
};
|
||||
@@ -546,3 +589,4 @@ public:
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -95,10 +95,97 @@ BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
|
||||
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
// helpers
|
||||
template <class T> struct identity { typedef T type; };
|
||||
|
||||
// take the Nth element in the tuple, or null_type if tuple is not
|
||||
// long enough
|
||||
|
||||
template <int N, class T>
|
||||
struct element_or_null_type {
|
||||
typedef typename
|
||||
detail::IF_type<
|
||||
(N < boost::tuples::length<T>::value),
|
||||
boost::tuples::element<N, T>,
|
||||
identity<null_type>
|
||||
>::type type;
|
||||
};
|
||||
|
||||
// Lambda functors all provide the sig member template for
|
||||
// querying their return type.
|
||||
// these type mappings implement the tools for that deduction
|
||||
|
||||
//type mapping to compute the new lambda functor resulting from a curried
|
||||
// call.
|
||||
template<class LF, int Args_expected, class SigArgs>
|
||||
struct curry_sig {
|
||||
|
||||
// First arg in SigArgs is the lambda functor type, that's why the -1
|
||||
BOOST_STATIC_CONSTANT(int, acount = boost::tuples::length<SigArgs>::value-1);
|
||||
|
||||
|
||||
// currying is only supported for 2- and 3-ary lambda functors, and
|
||||
// must be called by 1 or 2 arguments.
|
||||
// BOOST_STATIC_ASSERT(acount == 1 || acount == 2);
|
||||
// BOOST_STATIC_ASSERT(dig_arity<LF>::value == SECOND || dig_arity<LF>::value == THIRD);
|
||||
|
||||
|
||||
typedef typename detail::element_or_null_type<1, SigArgs>::type el_1;
|
||||
typedef typename detail::element_or_null_type<2, SigArgs>::type el_2;
|
||||
|
||||
typedef lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<Args_expected + 1, curry_action<acount> >,
|
||||
// remoce_const_refernce takes care that const null_type will
|
||||
// be null_type, that arrays are always stored as const refs,
|
||||
// that nonconst refs remain nonconst refs, and everything else goes
|
||||
// to const copy.
|
||||
|
||||
tuple<
|
||||
LF,
|
||||
typename detail::remove_const_reference<el_1>::type,
|
||||
typename detail::remove_const_reference<el_2>::type
|
||||
>,
|
||||
detail::reduce_arity<dig_arity<LF>::value, acount>::value
|
||||
>
|
||||
> type;
|
||||
};
|
||||
|
||||
// enter the normal return type deduction
|
||||
template <class LF, class SigArgs>
|
||||
struct eval_sig
|
||||
{
|
||||
typedef typename
|
||||
return_type<
|
||||
LF,
|
||||
open_args<
|
||||
detail::element_or_null_type<1, SigArgs>::type,
|
||||
detail::element_or_null_type<2, SigArgs>::type,
|
||||
detail::element_or_null_type<3, SigArgs>::type
|
||||
>
|
||||
>::type type;
|
||||
};
|
||||
|
||||
// either a normal evaluation, or a curried call
|
||||
template <class LF, int Args_expected, class SigArgs>
|
||||
struct lambda_functor_sig
|
||||
{
|
||||
typedef typename
|
||||
detail::IF_type<
|
||||
(boost::tuples::length<SigArgs>::value - 1 < Args_expected),
|
||||
detail::curry_sig<LF, Args_expected, SigArgs>,
|
||||
detail::eval_sig<LF, SigArgs>
|
||||
>::type type;
|
||||
};
|
||||
|
||||
} // end detail
|
||||
|
||||
// -- lambda_functor NONE ------------------------------------------------
|
||||
template <class Action, class Args>
|
||||
class lambda_functor<lambda_functor_args<Action, Args, NONE> >
|
||||
: public lambda_functor_base<Action, Args>
|
||||
: public lambda_functor_base<Action, Args>, public has_sig
|
||||
{
|
||||
public:
|
||||
typedef lambda_functor_base<Action, Args> inherited;
|
||||
@@ -112,7 +199,11 @@ public:
|
||||
(const lambda_functor<lambda_functor_args<Action, Args2, NONE> >& f)
|
||||
: inherited(f.args) {}
|
||||
|
||||
typename
|
||||
template <class SigArgs> struct sig {
|
||||
typedef typename
|
||||
detail::lambda_functor_sig<lambda_functor, 0, SigArgs>::type type;
|
||||
};
|
||||
|
||||
return_type<
|
||||
lambda_functor,
|
||||
open_args<null_type, null_type, null_type>
|
||||
@@ -155,6 +246,11 @@ public:
|
||||
(const lambda_functor<lambda_functor_args<Action, Args2, FIRST> >& f)
|
||||
: inherited(f.args) {}
|
||||
|
||||
template <class SigArgs> struct sig {
|
||||
typedef typename
|
||||
detail::lambda_functor_sig<lambda_functor, 1, SigArgs>::type type;
|
||||
};
|
||||
|
||||
template<class A>
|
||||
typename
|
||||
return_type<lambda_functor, open_args<A&, null_type, null_type> >::type
|
||||
@@ -181,7 +277,7 @@ public:
|
||||
// -- lambda_functor SECOND -------------------------------------------------
|
||||
template <class Action, class Args>
|
||||
class lambda_functor<lambda_functor_args<Action, Args, SECOND> >
|
||||
: public lambda_functor_base<Action, Args>
|
||||
: public lambda_functor_base<Action, Args>, public has_sig
|
||||
{
|
||||
public:
|
||||
typedef lambda_functor_base<Action, Args> inherited;
|
||||
@@ -195,6 +291,12 @@ public:
|
||||
(const lambda_functor<lambda_functor_args<Action, Args2, SECOND> >& f)
|
||||
: inherited(f.args) {}
|
||||
|
||||
|
||||
template <class SigArgs> struct sig {
|
||||
typedef typename
|
||||
detail::lambda_functor_sig<lambda_functor, 2, SigArgs>::type type;
|
||||
};
|
||||
|
||||
template<class A, class B>
|
||||
typename return_type<lambda_functor, open_args<A&, B&, null_type> >::type
|
||||
operator()(A& a, B& b) const
|
||||
@@ -207,24 +309,28 @@ public:
|
||||
|
||||
// currying call: creates another lambda functor
|
||||
template<class A>
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<3, curry_action<1> >,
|
||||
detail::bind_tuple_mapper<lambda_functor, const A>::type,
|
||||
FIRST
|
||||
>
|
||||
>
|
||||
sig<tuple<lambda_functor, A&> >::type
|
||||
// lambda_functor<
|
||||
// lambda_functor_args<
|
||||
// action<3, curry_action<1> >,
|
||||
// detail::bind_tuple_mapper<lambda_functor, const A>::type,
|
||||
// FIRST
|
||||
// >
|
||||
// >
|
||||
operator()(A& a) const
|
||||
{
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<3, curry_action<1> >,
|
||||
detail::bind_tuple_mapper<lambda_functor, const A>::type,
|
||||
FIRST
|
||||
>
|
||||
> ( typename
|
||||
detail::bind_tuple_mapper<lambda_functor, const A>::type(*this, a)
|
||||
typename sig<tuple<lambda_functor, A&> >::type
|
||||
// lambda_functor<
|
||||
// lambda_functor_args<
|
||||
// action<3, curry_action<1> >,
|
||||
// detail::bind_tuple_mapper<lambda_functor, const A>::type,
|
||||
// FIRST
|
||||
// >
|
||||
// >
|
||||
(
|
||||
tuple<lambda_functor,
|
||||
typename detail::remove_const_reference<A&>::type>(*this, a)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -241,7 +347,7 @@ public:
|
||||
|
||||
// -- lambda_functor THIRD -------------------------------------------------
|
||||
template <class Action, class Args>
|
||||
class lambda_functor<lambda_functor_args<Action, Args, THIRD> > : public lambda_functor_base<Action, Args>
|
||||
class lambda_functor<lambda_functor_args<Action, Args, THIRD> > : public lambda_functor_base<Action, Args>, public has_sig
|
||||
{
|
||||
public:
|
||||
typedef lambda_functor_base<Action, Args> inherited;
|
||||
@@ -255,6 +361,11 @@ public:
|
||||
(const lambda_functor<lambda_functor_args<Action, Args2, THIRD> >& f)
|
||||
: inherited(f.args) {}
|
||||
|
||||
template <class SigArgs> struct sig {
|
||||
typedef typename
|
||||
detail::lambda_functor_sig<lambda_functor, 3, SigArgs>::type type;
|
||||
};
|
||||
|
||||
template<class A, class B, class C>
|
||||
typename return_type<lambda_functor, open_args<A&, B&, C&> >::type
|
||||
operator()(A& a, B& b, C& c) const
|
||||
@@ -270,49 +381,56 @@ public:
|
||||
|
||||
// currying call, one argument still missing
|
||||
template<class A, class B>
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<4, curry_action<2> >,
|
||||
detail::bind_tuple_mapper<lambda_functor, const A, const B>::type,
|
||||
FIRST
|
||||
>
|
||||
>
|
||||
sig<tuple<lambda_functor, A&, B&> >::type
|
||||
// lambda_functor<
|
||||
// lambda_functor_args<
|
||||
// action<4, curry_action<2> >,
|
||||
// detail::bind_tuple_mapper<lambda_functor, const A, const B>::type,
|
||||
// FIRST
|
||||
// >
|
||||
// >
|
||||
operator()(A& a, B& b) const
|
||||
{
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<4, curry_action<2> >,
|
||||
detail::bind_tuple_mapper<lambda_functor, const A, const B>::type,
|
||||
FIRST
|
||||
>
|
||||
>
|
||||
( typename
|
||||
detail::bind_tuple_mapper<lambda_functor, const A, const B>::type
|
||||
(*this, a, b)
|
||||
typename sig<tuple<lambda_functor, A&, B&> >::type
|
||||
// lambda_functor<
|
||||
// lambda_functor_args<
|
||||
// action<4, curry_action<2> >,
|
||||
// detail::bind_tuple_mapper<lambda_functor, const A, const B>::type,
|
||||
// FIRST
|
||||
// >
|
||||
// >
|
||||
( tuple<
|
||||
lambda_functor,
|
||||
typename detail::remove_const_reference<A&>::type,
|
||||
typename detail::remove_const_reference<B&>::type
|
||||
> (*this, a, b)
|
||||
);
|
||||
}
|
||||
|
||||
// currying call, two arguments still missing
|
||||
template<class A>
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<4, curry_action<1> >,
|
||||
detail::bind_tuple_mapper<lambda_functor, const A>::type,
|
||||
SECOND
|
||||
>
|
||||
>
|
||||
sig<tuple<lambda_functor, A&> >::type
|
||||
// lambda_functor<
|
||||
// lambda_functor_args<
|
||||
// action<4, curry_action<1> >,
|
||||
// detail::bind_tuple_mapper<lambda_functor, const A>::type,
|
||||
// SECOND
|
||||
// >
|
||||
// >
|
||||
operator()(A& a) const
|
||||
{
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<4, curry_action<1> >,
|
||||
detail::bind_tuple_mapper<lambda_functor, const A>::type,
|
||||
SECOND
|
||||
>
|
||||
> ( typename
|
||||
detail::bind_tuple_mapper<lambda_functor, const A>::type(*this, a)
|
||||
typename sig<tuple<lambda_functor, A&> >::type
|
||||
// lambda_functor<
|
||||
// lambda_functor_args<
|
||||
// action<4, curry_action<1> >,
|
||||
// detail::bind_tuple_mapper<lambda_functor, const A>::type,
|
||||
// SECOND
|
||||
// >
|
||||
// >
|
||||
(
|
||||
tuple<lambda_functor, typename detail::remove_const_reference<A&>::type>(*this, a)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -228,6 +228,10 @@ struct parameter_traits_<const volatile boost::reference_wrapper<T>, Any >{
|
||||
typedef T& type;
|
||||
};
|
||||
|
||||
template<class Any>
|
||||
struct parameter_traits_<void, Any> {
|
||||
typedef void type;
|
||||
};
|
||||
} // end namespace detail
|
||||
|
||||
|
||||
@@ -270,6 +274,10 @@ struct const_copy_argument<T&> {
|
||||
typedef typename detail::generate_error<T&>::references_not_allowed type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct const_copy_argument<void> {
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
|
||||
// The default is non-const reference -------------------------
|
||||
@@ -308,6 +316,11 @@ struct reference_argument<const volatile lambda_functor<Arg> > {
|
||||
typedef lambda_functor<Arg> type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct reference_argument<void> {
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Array to pointer conversion
|
||||
@@ -337,7 +350,7 @@ struct array_to_pointer <T (&) [N]> {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// The call_traits for bind
|
||||
// Honours the reference_wrapper class.
|
||||
// Respects the reference_wrapper class.
|
||||
|
||||
// These templates are used outside of bind functions as well.
|
||||
// the bind_tuple_mapper provides a shorter notation for default
|
||||
@@ -414,6 +427,11 @@ struct bind_traits<const reference_wrapper<T> >{
|
||||
typedef T& type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct bind_traits<void> {
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <
|
||||
@@ -436,6 +454,17 @@ struct bind_tuple_mapper {
|
||||
typename bind_traits<T9>::type> type;
|
||||
};
|
||||
|
||||
// bind_traits, except map const T& -> const T
|
||||
// this is needed e.g. in currying. Const reference arguments can
|
||||
// refer to temporaries, so it is not safe to store them as references.
|
||||
template <class T> struct remove_const_reference {
|
||||
typedef typename bind_traits<T>::type type;
|
||||
};
|
||||
|
||||
template <class T> struct remove_const_reference<const T&> {
|
||||
typedef const T type;
|
||||
};
|
||||
|
||||
|
||||
// maps the bind argument types to the resulting lambda functor type
|
||||
template <
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
|
||||
// -- artihmetic ----------------------
|
||||
|
||||
class plus_action {};
|
||||
@@ -89,7 +90,7 @@ template <class Action> class post_increment_decrement_action;
|
||||
#endif
|
||||
|
||||
#define BOOST_LAMBDA_BINARY_ACTION(OPER_SYMBOL, GROUP, OPER_NAME) \
|
||||
template<> class GROUP < OPER_NAME> {\
|
||||
template<> class GROUP < OPER_NAME> : public protectable {\
|
||||
public: \
|
||||
template<class RET, class A, class B>\
|
||||
static RET apply(A& a, B& b) { \
|
||||
@@ -135,7 +136,7 @@ BOOST_LAMBDA_BINARY_ACTION(^=,bitwise_assignment_action,xor_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(=,other_action, assignment_action)
|
||||
// subscript is done directly because BOOST_LAMBDA_BINARY_ACTION currently doesn't handle it.
|
||||
|
||||
template<> class other_action<subscript_action> {
|
||||
template<> class other_action<subscript_action> : public protectable {
|
||||
public:
|
||||
template<class RET, class A, class B>
|
||||
static RET apply(A& a, B& b) { return a[b]; }
|
||||
@@ -157,7 +158,7 @@ public:
|
||||
#endif
|
||||
|
||||
#define BOOST_LAMBDA_PREFIX_UNARY_ACTION(OPER_SYMBOL, GROUP, OPER_NAME) \
|
||||
template<> class GROUP <OPER_NAME> {\
|
||||
template<> class GROUP <OPER_NAME> : public protectable {\
|
||||
public: \
|
||||
template<class RET, class A>\
|
||||
static RET apply(A& a) { return OPER_SYMBOL a; }\
|
||||
@@ -181,7 +182,7 @@ BOOST_LAMBDA_PREFIX_UNARY_ACTION( , other_action, identity_action)
|
||||
#endif
|
||||
|
||||
#define BOOST_LAMBDA_POSTFIX_UNARY_ACTION(OPER_SYMBOL, GROUP, OPER_NAME) \
|
||||
template<> class GROUP <OPER_NAME> {\
|
||||
template<> class GROUP <OPER_NAME> : public protectable {\
|
||||
public: \
|
||||
template<class RET, class A>\
|
||||
static RET apply(A& a) { return a OPER_SYMBOL; }\
|
||||
|
||||
@@ -176,7 +176,7 @@ public:
|
||||
// functor for one application, unlambda for good.
|
||||
|
||||
template <class Arg>
|
||||
class non_lambda_functor {
|
||||
class non_lambda_functor : public has_sig {
|
||||
lambda_functor<Arg> lf; // a lambda functor
|
||||
public:
|
||||
|
||||
@@ -184,32 +184,42 @@ public:
|
||||
// The result type must be deducible without knowing the arguments
|
||||
|
||||
// TODO: check that passing unspecified as open args fails
|
||||
typedef typename
|
||||
return_type<Arg,
|
||||
open_args<detail::unspecified,
|
||||
detail::unspecified,
|
||||
detail::unspecified> >::type
|
||||
result_type;
|
||||
// typedef typename
|
||||
// return_type<Arg,
|
||||
// open_args<detail::unspecified,
|
||||
// detail::unspecified,
|
||||
// detail::unspecified> >::type
|
||||
// result_type;
|
||||
|
||||
|
||||
template <class SigArgs> struct sig {
|
||||
typedef typename
|
||||
lambda_functor<Arg>::template sig<SigArgs>::type type;
|
||||
};
|
||||
|
||||
non_lambda_functor(const lambda_functor<Arg>& a) : lf(a) {}
|
||||
|
||||
result_type operator()() const {
|
||||
return lf.template ret_call<result_type>();
|
||||
sig<tuple<lambda_functor<Arg> > >::type
|
||||
operator()() const {
|
||||
return lf.template ret_call<typename sig<tuple<lambda_functor<Arg> > >::type>();
|
||||
}
|
||||
|
||||
template<class A>
|
||||
result_type operator()(A& a) const {
|
||||
return lf.template ret_call<result_type>(a);
|
||||
sig<tuple<lambda_functor<Arg>, A&> >::type
|
||||
operator()(A& a) const {
|
||||
return lf.template ret_call<typename sig<tuple<lambda_functor<Arg>, A&> >::type >(a);
|
||||
}
|
||||
|
||||
template<class A, class B>
|
||||
result_type operator()(A& a, B& b) const {
|
||||
return lf.template ret_call<result_type>(a, b);
|
||||
sig<tuple<lambda_functor<Arg>, A&, B&> >::type
|
||||
operator()(A& a, B& b) const {
|
||||
return lf.template ret_call<typename sig<tuple<lambda_functor<Arg>, A&, B&> >::type >(a, b);
|
||||
}
|
||||
|
||||
template<class A, class B, class C>
|
||||
result_type operator()(A& a, B& b, C& c) const {
|
||||
return lf.template ret_call<result_type>(a, b, c);
|
||||
sig<tuple<lambda_functor<Arg>, A&, B&, C&> >::type
|
||||
operator()(A& a, B& b, C& c) const {
|
||||
return lf.template ret_call<typename sig<tuple<lambda_functor<Arg>, A&, B&, C&> >::type>(a, b, c);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace lambda {
|
||||
|
||||
// So, in the case the return type deduction should fail, it should not
|
||||
// fail directly, but rather result in a valid but wrong return type,
|
||||
// causing a compile time error, if the function is really called.
|
||||
// causing a compile time error only if the function is really called.
|
||||
|
||||
namespace detail {
|
||||
|
||||
@@ -67,6 +67,13 @@ struct return_type {
|
||||
typedef Arg type;
|
||||
};
|
||||
|
||||
|
||||
// different arities:
|
||||
template <class Act, class A1> class return_type_1; // 1-ary actions
|
||||
template <class Act, class A1, class A2> class return_type_2; // 2-ary
|
||||
template <class Act, class Args> class return_type_N; // >3- ary
|
||||
|
||||
|
||||
// Unary actions (result from unary operators)
|
||||
// do not have a default return type.
|
||||
template<class Act, class A> struct return_type_1 {
|
||||
@@ -74,30 +81,50 @@ template<class Act, class A> struct return_type_1 {
|
||||
detail::return_type_deduction_failure<return_type_1> type;
|
||||
};
|
||||
|
||||
// read the comments for return_type_2_0
|
||||
template <class Act, class A> struct return_type_1_0 {
|
||||
|
||||
typedef typename boost::remove_reference<A>::type A1;
|
||||
|
||||
typedef typename
|
||||
detail::IF_type<
|
||||
boost::is_function<A1>::value,
|
||||
boost::add_reference<A1>,
|
||||
boost::add_const<A1>
|
||||
>::type A2;
|
||||
// read the comments for return_type_2_protect
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class A>
|
||||
class protect_conversion {
|
||||
|
||||
// T -> const T
|
||||
// T& -> T&
|
||||
// const T& -> const T
|
||||
// function& -> function&
|
||||
// const array& -> const array&
|
||||
// lambda functors are not stored as references
|
||||
// function reference types are function reference types
|
||||
typedef typename boost::remove_reference<A>::type A1;
|
||||
|
||||
typedef typename detail::IF<
|
||||
boost::is_reference<A>::value
|
||||
&& !boost::is_const<A1>::value
|
||||
&& !is_lambda_functor<A1>::value,
|
||||
A,
|
||||
const_copy_argument<A1>::type // handles funtion and array type correctly
|
||||
>::RET type;
|
||||
};
|
||||
|
||||
} // end detail
|
||||
|
||||
template <class Act, class A> struct return_type_1_protect {
|
||||
|
||||
typedef typename
|
||||
detail::IF<
|
||||
is_lambda_functor<A>::value,
|
||||
is_lambda_functor<A>::value,
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, Act>,
|
||||
tuple<A2>,
|
||||
tuple<typename detail::protect_conversion<A>::type>,
|
||||
dig_arity<A>::value
|
||||
>
|
||||
>,
|
||||
typename return_type_1<Act, A>::type
|
||||
>::RET type;
|
||||
|
||||
};
|
||||
|
||||
// binary actions ---------------------------------------------------
|
||||
@@ -108,36 +135,41 @@ typedef typename
|
||||
// (if protect) has been used.
|
||||
// Thus, if one of the parameter types is a lambda functor, the result
|
||||
// is a lambda functor as well.
|
||||
// We need to make a conservative choise here, all arguments in the
|
||||
// resulting lambda functor will be stored as const copies. The true
|
||||
// result type may have non-const reference arguments, but it is either
|
||||
// impossible or very hard to find out that. And references here might
|
||||
// be unsafe (references to temporaries that do not exist).
|
||||
// We need to make a conservative choise here.
|
||||
// The resulting lambda functor stores all const reference arguments as
|
||||
// const copies. References to non-const are stored as such.
|
||||
// So if the source of the argument is an const open argument, a bound
|
||||
// argument stroed as a const reference, or a function returning a
|
||||
// const reference, that information is lost. There is no way of
|
||||
// telling apart 'real const references' from just 'LL internal
|
||||
// const references' (or it would be really hard)
|
||||
|
||||
// The return type is a subclass of lambda_functor, which has a converting
|
||||
// copy constructor. It can copy any lambda functor, that has the same
|
||||
// action type and code, and a copy compatible argument tuple.
|
||||
|
||||
template <class Act, class A, class B> struct return_type_2_0 {
|
||||
|
||||
typedef typename boost::remove_reference<A>::type A1;
|
||||
typedef typename boost::remove_reference<B>::type B1;
|
||||
|
||||
// adding const to a function type fails, these tests are to
|
||||
// avoid that. Note that only the true branch is instantiated with this IF
|
||||
typedef typename
|
||||
detail::IF_type<
|
||||
boost::is_function<A1>::value,
|
||||
boost::add_reference<A1>,
|
||||
boost::add_const<A1>
|
||||
>::type A2;
|
||||
template <class Act, class A, class B> struct return_type_2_protect {
|
||||
|
||||
typedef typename
|
||||
detail::IF_type<
|
||||
boost::is_function<B1>::value,
|
||||
boost::add_reference<B1>,
|
||||
boost::add_const<B1>
|
||||
>::type B2;
|
||||
// typedef typename boost::remove_reference<A>::type A1;
|
||||
// typedef typename boost::remove_reference<B>::type B1;
|
||||
|
||||
// // adding const to a function type fails, these tests are to
|
||||
// // avoid that. Note that only the true branch is instantiated with this IF
|
||||
// typedef typename
|
||||
// detail::IF_type<
|
||||
// !is_lambda_functor<A1>::value && (boost::is_function<A1>::value || !(boost::is_const<A1>::value)),
|
||||
// boost::add_reference<A1>,
|
||||
// boost::add_const<A1>
|
||||
// >::type A2;
|
||||
|
||||
// typedef typename
|
||||
// detail::IF_type<
|
||||
// !is_lambda_functor<B1>::value && ( boost::is_function<B1>::value || !(boost::is_const<B1>::value)),
|
||||
// boost::add_reference<B1>,
|
||||
// boost::add_const<B1>
|
||||
// >::type B2;
|
||||
|
||||
|
||||
typedef typename
|
||||
@@ -146,7 +178,8 @@ typedef typename
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<2, Act>,
|
||||
tuple<A2, B2>,
|
||||
tuple<typename detail::protect_conversion<A>::type,
|
||||
typename detail::protect_conversion<B>::type>,
|
||||
combine_arities<A, B>::value
|
||||
>
|
||||
>,
|
||||
@@ -154,61 +187,17 @@ typedef typename
|
||||
>::RET type;
|
||||
};
|
||||
|
||||
// Was needed for a while, not now, since no return type deduction depends
|
||||
// on more than two arguments
|
||||
|
||||
// template <class Act, class A, class B, class C> struct return_type_3_0 {
|
||||
|
||||
// typedef typename boost::remove_reference<A>::type A1;
|
||||
// typedef typename boost::remove_reference<B>::type B1;
|
||||
// typedef typename boost::remove_reference<C>::type C1;
|
||||
|
||||
// // adding const to a function type fails, these tests are to
|
||||
// // avoid that. Note that only the true branch is instantiated with this IF
|
||||
// typedef typename
|
||||
// detail::IF_type<
|
||||
// boost::is_function<A1>::value,
|
||||
// boost::add_reference<A1>,
|
||||
// boost::add_const<A1>
|
||||
// >::type A2;
|
||||
|
||||
// typedef typename
|
||||
// detail::IF_type<
|
||||
// boost::is_function<B1>::value,
|
||||
// boost::add_reference<B1>,
|
||||
// boost::add_const<B1>
|
||||
// >::type B2;
|
||||
|
||||
// typedef typename
|
||||
// detail::IF_type<
|
||||
// boost::is_function<C1>::value,
|
||||
// boost::add_reference<C1>,
|
||||
// boost::add_const<C1>
|
||||
// >::type C2;
|
||||
|
||||
|
||||
// typedef typename
|
||||
// detail::IF<
|
||||
// is_lambda_functor<A>::value || is_lambda_functor<B>::value ||
|
||||
// is_lambda_functor<C>::value,
|
||||
// lambda_functor<
|
||||
// lambda_functor_args<
|
||||
// action<3, Act>,
|
||||
// tuple<A2, B2, C2>,
|
||||
// combine_arities<A, B, C>::value
|
||||
// >
|
||||
// >,
|
||||
// typename return_type_1<Act, A>::type
|
||||
// >::RET type;
|
||||
|
||||
// // unary function action (it is binary action)
|
||||
// // If a function object overloads operator(), the return type could depend
|
||||
// // on the argument types. This is not taken into consideration.
|
||||
// template<class A, class B, class Ret>
|
||||
// struct return_type_2<function_action<2, Ret>, A, B> {
|
||||
// typedef typename return_type_1<function_action<1, Ret>, A>::type type;
|
||||
// };
|
||||
|
||||
// unary function action (it is binary action)
|
||||
// If a function object overloads operator(), the return type could depend
|
||||
// on the argument types. This is not taken into consideration.
|
||||
template<class A, class B, class Ret>
|
||||
struct return_type_2<function_action<2, Ret>, A, B> {
|
||||
typedef typename return_type_1<function_action<1, Ret>, A>::type type;
|
||||
};
|
||||
|
||||
// reduce to lambda_functor_args
|
||||
// to be on the safe side, constness and references are stripped away,
|
||||
@@ -275,20 +264,66 @@ struct return_type<placeholder<EXCEPTION>, Open> {
|
||||
// on the argument types. This is not taken into consideration.
|
||||
|
||||
// use the return type given in the bind invocation as bind<Ret>(...)
|
||||
template<int I, class A, class Ret>
|
||||
struct return_type_1<function_action<I, Ret>, A > {
|
||||
template<class A, class Ret>
|
||||
struct return_type_1<function_action<1, Ret>, A > {
|
||||
typedef Ret type;
|
||||
};
|
||||
template<class A, class B, class Ret>
|
||||
struct return_type_2<function_action<2, Ret>, A, B > {
|
||||
typedef Ret type;
|
||||
};
|
||||
template<int I, class Args, class Ret>
|
||||
struct return_type_N<function_action<I, Ret>, Args> {
|
||||
typedef Ret type;
|
||||
};
|
||||
|
||||
// Ret is detail::unspecified, so try to deduce return type
|
||||
template<int I, class A>
|
||||
struct return_type_1<function_action<I, detail::unspecified>, A > {
|
||||
typedef typename function_adaptor_sub<
|
||||
typename detail::remove_reference_and_cv<A>::type
|
||||
>::type type;
|
||||
template<class A>
|
||||
struct return_type_1<function_action<1, detail::unspecified>, A > {
|
||||
typedef typename function_adaptor_with_actuals<typename tuple<A>::inherited>::type type;
|
||||
};
|
||||
template<class A, class B>
|
||||
struct return_type_2<function_action<2, detail::unspecified>, A, B > {
|
||||
typedef typename function_adaptor_with_actuals<tuple<A, B>::inherited>::type type;
|
||||
};
|
||||
template<int I, class Args>
|
||||
struct return_type_N<function_action<I, detail::unspecified>, Args > {
|
||||
typedef typename function_adaptor_with_actuals<Args>::type type;
|
||||
};
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class T, class Open>
|
||||
struct map_to_return_types {
|
||||
typedef typename return_type<
|
||||
typename boost::tuples::access_traits<typename T::head_type>::const_type,
|
||||
Open
|
||||
>::type ret_type;
|
||||
|
||||
// const and reference is added, so that specializations for return_type_1
|
||||
// become easier (we can rely on the Args always being references, so the
|
||||
// number of specializations doesn't explode.
|
||||
// Note! If T is already a reference to nonconst, it will remain that way
|
||||
// To return type deduction, const T& is the same as rvalue T
|
||||
|
||||
typedef typename boost::add_reference<
|
||||
typename boost::add_const<ret_type>::type
|
||||
>::type ref_to_const_ret_type;
|
||||
|
||||
typedef boost::tuples::cons<
|
||||
ref_to_const_ret_type,
|
||||
typename map_to_return_types<typename T::tail_type, Open>::type
|
||||
> type;
|
||||
};
|
||||
|
||||
template <class Open>
|
||||
struct map_to_return_types<boost::tuples::null_type, Open> {
|
||||
typedef boost::tuples::null_type type;
|
||||
};
|
||||
|
||||
} // end detail
|
||||
|
||||
// general unary and binary actions
|
||||
template<class Act, class Args, int Code, class Open>
|
||||
struct return_type<lambda_functor_args<action<1, Act>, Args, Code>, Open> {
|
||||
@@ -309,7 +344,12 @@ struct return_type<lambda_functor_args<action<1, Act>, Args, Code>, Open> {
|
||||
|
||||
public:
|
||||
|
||||
typedef typename return_type_1_0<Act, refc_A_type>::type type;
|
||||
typedef typename
|
||||
detail::IF_type<
|
||||
detail::is_protectable_action<Act>::value,
|
||||
return_type_1_protect<Act, refc_A_type>,
|
||||
return_type_1<Act, refc_A_type>
|
||||
>::type type;
|
||||
|
||||
};
|
||||
|
||||
@@ -334,38 +374,103 @@ class return_type<lambda_functor_args<action<2, Act>, Args, Code>, Open> {
|
||||
>::type refc_B_type;
|
||||
|
||||
public:
|
||||
typedef typename return_type_2_0<Act, refc_A_type, refc_B_type>::type type;
|
||||
typedef typename
|
||||
detail::IF_type<
|
||||
detail::is_protectable_action<Act>::value,
|
||||
return_type_2_protect<Act, refc_A_type, refc_B_type>,
|
||||
return_type_2<Act, refc_A_type, refc_B_type>
|
||||
>::type type;
|
||||
|
||||
};
|
||||
|
||||
// Was needed for a while, not now, since no return type deduction depends
|
||||
// on more than two arguments
|
||||
// This is the general case. Will match any action with arity >= 3
|
||||
template<int I, class Act, class Args, int Code, class Open>
|
||||
class return_type<lambda_functor_args<action<I, Act>, Args, Code>, Open> {
|
||||
typedef typename detail::map_to_return_types<Args, Open>::type actual_args;
|
||||
public:
|
||||
typedef typename return_type_N<Act, actual_args>::type type;
|
||||
};
|
||||
|
||||
// template<class Act, class Args, int Code, class Open>
|
||||
// struct return_type<lambda_functor_args<action<3, Act>, Args, Code>, Open> {
|
||||
// typedef
|
||||
// typename return_type_3_0<
|
||||
// Act,
|
||||
// typename return_type<
|
||||
// typename detail::tuple_element_as_reference<0, Args>::type,
|
||||
// Open
|
||||
// >::type,
|
||||
// typename return_type<
|
||||
// typename detail::tuple_element_as_reference<1, Args>::type,
|
||||
// Open
|
||||
// >::type,
|
||||
// typename return_type<
|
||||
// typename detail::tuple_element_as_reference<2, Args>::type,
|
||||
// Open
|
||||
// >::type
|
||||
// >::type
|
||||
// type;
|
||||
// class return_type<lambda_functor_args<action<3, Act>, Args, Code>, Open> {
|
||||
|
||||
// typedef typename return_type<
|
||||
// typename detail::tuple_element_as_reference<0, Args>::type,
|
||||
// Open
|
||||
// >::type A_type;
|
||||
|
||||
// typedef typename return_type<
|
||||
// typename detail::tuple_element_as_reference<1, Args>::type,
|
||||
// Open
|
||||
// >::type B_type;
|
||||
|
||||
// typedef typename return_type<
|
||||
// typename detail::tuple_element_as_reference<2, Args>::type,
|
||||
// Open
|
||||
// >::type C_type;
|
||||
|
||||
// typedef typename boost::add_reference<
|
||||
// typename boost::add_const<A_type>::type
|
||||
// >::type refc_A_type;
|
||||
// typedef typename boost::add_reference<
|
||||
// typename boost::add_const<B_type>::type
|
||||
// >::type refc_B_type;
|
||||
// typedef typename boost::add_reference<
|
||||
// typename boost::add_const<C_type>::type
|
||||
// >::type refc_C_type;
|
||||
|
||||
// public:
|
||||
// // no 3- or higher ary protectable actions exist, no need to check
|
||||
// typedef typename return_type_3<Act, refc_A_type, refc_B_type, refc_C_type>::type type;
|
||||
// };
|
||||
|
||||
// // 4 args or more (must be a function action)
|
||||
// template<int I, class Act, class Args, int Code, class Open>
|
||||
// class return_type<lambda_functor_args<action<I, Act>, Args, Code>, Open> {
|
||||
|
||||
// typedef typename return_type<
|
||||
// typename detail::tuple_element_as_reference<0, Args>::type,
|
||||
// Open
|
||||
// >::type A_type;
|
||||
|
||||
// typedef typename return_type<
|
||||
// typename detail::tuple_element_as_reference<1, Args>::type,
|
||||
// Open
|
||||
// >::type B_type;
|
||||
|
||||
// typedef typename return_type<
|
||||
// typename detail::tuple_element_as_reference<2, Args>::type,
|
||||
// Open
|
||||
// >::type C_type;
|
||||
|
||||
// typedef typename return_type<
|
||||
// typename detail::tuple_element_as_reference<3, Args>::type,
|
||||
// Open
|
||||
// >::type D_type;
|
||||
|
||||
// typedef typename boost::add_reference<
|
||||
// typename boost::add_const<A_type>::type
|
||||
// >::type refc_A_type;
|
||||
// typedef typename boost::add_reference<
|
||||
// typename boost::add_const<B_type>::type
|
||||
// >::type refc_B_type;
|
||||
// typedef typename boost::add_reference<
|
||||
// typename boost::add_const<C_type>::type
|
||||
// >::type refc_C_type;
|
||||
// typedef typename boost::add_reference<
|
||||
// typename boost::add_const<D_type>::type
|
||||
// >::type refc_D_type;
|
||||
|
||||
// public:
|
||||
// typedef typename return_type_4<Act, refc_A_type, refc_B_type, refc_C_type, refc_D_type>::type type;
|
||||
// };
|
||||
|
||||
|
||||
|
||||
// special case for comma action:
|
||||
// As the return type needs to be exactly the type of the rightmost argument,
|
||||
// we cannot add a const and reference (we need to preserve rvalueness)
|
||||
// note, that return_type_2_0 is still called, so user can overload
|
||||
// note, that return_type_2_protect is still called, so user can overload
|
||||
// return_type_2 for user defined types.
|
||||
|
||||
template<class Args, int Code, class Open>
|
||||
@@ -383,7 +488,7 @@ class return_type<lambda_functor_args<action<2, other_action<comma_action> >, Ar
|
||||
|
||||
public:
|
||||
typedef typename
|
||||
return_type_2_0<other_action<comma_action>, A_type, B_type>::type type;
|
||||
return_type_2_protect<other_action<comma_action>, A_type, B_type>::type type;
|
||||
};
|
||||
|
||||
// protect action:
|
||||
@@ -432,31 +537,31 @@ struct return_type<lambda_functor_args<action<4, curry_action<2> >, Args, Code>,
|
||||
|
||||
|
||||
|
||||
// 3 arguments or more ---------------------------------------------
|
||||
// this must be a function_action. Note that the previous unary and binary
|
||||
// specalisations take care of nullary and unary function adaptors, that is,
|
||||
// unary and binary actions.
|
||||
// Since function_actions determine the return type based on the function
|
||||
// object only, we can ignore the arguments and reuse return_type_1.
|
||||
// // 3 arguments or more ---------------------------------------------
|
||||
// // this must be a function_action. Note that the previous unary and binary
|
||||
// // specalisations take care of nullary and unary function adaptors, that is,
|
||||
// // unary and binary actions.
|
||||
// // Since function_actions determine the return type based on the function
|
||||
// // object only, we can ignore the arguments and reuse return_type_1.
|
||||
|
||||
template <int I, class Act, class Args, int Code, class Open>
|
||||
class return_type<lambda_functor_args<action<I, Act>, Args, Code>, Open> {
|
||||
// template <int I, class Act, class Args, int Code, class Open>
|
||||
// class return_type<lambda_functor_args<action<I, Act>, Args, Code>, Open> {
|
||||
|
||||
typedef typename return_type<
|
||||
typename detail::tuple_element_as_reference<0, Args>::type,
|
||||
Open
|
||||
>::type A_type;
|
||||
// typedef typename return_type<
|
||||
// typename detail::tuple_element_as_reference<0, Args>::type,
|
||||
// Open
|
||||
// >::type A_type;
|
||||
|
||||
// reference is added, so that specializations for return_type_1
|
||||
// become easier.
|
||||
typedef typename boost::add_reference<
|
||||
typename boost::add_const<A_type>::type
|
||||
>::type refc_A_type;
|
||||
// // reference is added, so that specializations for return_type_1
|
||||
// // become easier.
|
||||
// typedef typename boost::add_reference<
|
||||
// typename boost::add_const<A_type>::type
|
||||
// >::type refc_A_type;
|
||||
|
||||
public:
|
||||
// public:
|
||||
|
||||
typedef typename return_type_1_0<Act, refc_A_type>::type type;
|
||||
};
|
||||
// typedef typename return_type_1_protect<Act, refc_A_type>::type type;
|
||||
// };
|
||||
|
||||
// The explicit return type action case, it is unary
|
||||
template<class RET, class Args, int Code, class Open>
|
||||
@@ -486,6 +591,13 @@ struct return_type<lambda_functor_args<action<2, return_void_action<Act> >,
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
template<class Act, class Args, int Code, class Open>
|
||||
struct return_type<lambda_functor_args<action<3, return_void_action<Act> >,
|
||||
Args, Code>, Open >
|
||||
{
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
template<int I, class Act, class Args, int Code, class Open>
|
||||
struct return_type<lambda_functor_args<action<I, return_void_action<Act> >,
|
||||
Args, Code>, Open >
|
||||
|
||||
Reference in New Issue
Block a user