2
0
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:
Jaakko Järvi
2002-01-10 20:54:11 +00:00
parent 682939bf35
commit afaacdc785
8 changed files with 558 additions and 218 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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