2
0
mirror of https://github.com/boostorg/lambda.git synced 2026-01-27 19:02:15 +00:00

added support for protect, unlambda, currying and break_const

[SVN r12139]
This commit is contained in:
Jaakko Järvi
2001-12-21 19:28:31 +00:00
parent 2c8b1949ec
commit cb2c689df7
8 changed files with 311 additions and 2 deletions

View File

@@ -424,6 +424,7 @@ struct return_type<
template<class Args>
class
lambda_functor_base<action<4, return_void_action<forloop_action> >, Args> {
public:
Args args;
public:
explicit lambda_functor_base(const Args& a) : args(a) {}
@@ -442,6 +443,7 @@ public:
template<class Args>
class
lambda_functor_base<action<3, return_void_action<forloop_action> >, Args> {
public:
Args args;
public:
explicit lambda_functor_base(const Args& a) : args(a) {}
@@ -459,6 +461,7 @@ public:
template<class Args>
class
lambda_functor_base<action<2, return_void_action<whileloop_action> >, Args> {
public:
Args args;
public:
explicit lambda_functor_base(const Args& a) : args(a) {}
@@ -475,6 +478,7 @@ public:
template<class Args>
class
lambda_functor_base<action<1, return_void_action<whileloop_action> >, Args> {
public:
Args args;
public:
explicit lambda_functor_base(const Args& a) : args(a) {}
@@ -490,6 +494,7 @@ public:
template<class Args>
class
lambda_functor_base<action<2, return_void_action<dowhileloop_action> >, Args> {
public:
Args args;
public:
explicit lambda_functor_base(const Args& a) : args(a) {}
@@ -506,6 +511,7 @@ public:
template<class Args>
class
lambda_functor_base<action<1, return_void_action<dowhileloop_action> >, Args> {
public:
Args args;
public:
explicit lambda_functor_base(const Args& a) : args(a) {}
@@ -521,6 +527,7 @@ public:
template<class Args>
class
lambda_functor_base<action<2, return_void_action<ifthen_action> >, Args> {
public:
Args args;
public:
explicit lambda_functor_base(const Args& a) : args(a) {}
@@ -535,6 +542,7 @@ public:
template<class Args>
class
lambda_functor_base<action<3, return_void_action<ifthenelse_action> >, Args> {
public:
Args args;
public:
explicit lambda_functor_base(const Args& a) : args(a) {}
@@ -552,6 +560,7 @@ public:
template<class Args>
class
lambda_functor_base<action<3, other_action<ifthenelsereturn_action> >, Args> {
public:
Args args;
public:
explicit lambda_functor_base(const Args& a) : args(a) {}

View File

@@ -57,6 +57,7 @@ struct nth_return_type {
template<class RET, class Args>
class lambda_functor_base<action<1, explicit_return_type_action<RET> >, Args>
{
public:
Args args;
public:
@@ -77,6 +78,7 @@ public:
template<class Args>
class lambda_functor_base<action<1, protect_action >, Args>
{
public:
Args args;
public:
@@ -90,6 +92,65 @@ public:
};
// The work of curry action is not defined in action class apply,
// but rather directly in lambda_functor_base::call
// The argument substitution would be messed up otherwise.
// the curry_action 2-ary lambda_functor, one curried arg -------------------
template<class Args>
class lambda_functor_base<action<3, curry_action<1> >, Args>
{
public:
Args args;
public:
explicit lambda_functor_base(const Args& a) : args(a) {}
template<class RET, class A, class B, class C>
RET call(A& a, B& b, C& c) const
{
return boost::tuples::get<0>(args).template ret_call<RET>(
boost::tuples::get<1>(args), a);
}
};
// the curry_action case, 3-ary lambda functor, one curried arg --------------
template<class Args>
class lambda_functor_base<action<4, curry_action<1> >, Args>
{
public:
Args args;
public:
explicit lambda_functor_base(const Args& a) : args(a) {}
template<class RET, class A, class B, class C>
RET call(A& a, B& b, C& c) const
{
return boost::tuples::get<0>(args).template ret_call<RET>(
boost::tuples::get<1>(args), a, b);
}
};
// the curry_action case, 3-ary lambda functor, two curried args -------------
template<class Args>
class lambda_functor_base<action<4, curry_action<2> >, Args>
{
public:
Args args;
public:
explicit lambda_functor_base(const Args& a) : args(a) {}
template<class RET, class A, class B, class C>
RET call(A& a, B& b, C& c) const
{
return boost::tuples::get<0>(args).template ret_call<RET>(
boost::tuples::get<1>(args), boost::tuples::get<2>(args), a);
}
};
#if defined BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART
#error "Multiple defines of BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART"
#endif
@@ -98,6 +159,7 @@ public:
template<class Act, class Args>\
class lambda_functor_base<action<ARITY, Act>, Args> \
{\
public:\
Args args;\
public:\
\

View File

@@ -88,6 +88,7 @@ public:
// default constructor (do nothing)
// bug in gcc 2.95.2 for const template objects.
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
@@ -186,11 +187,35 @@ public:
>::type>(a, b, const_null_type());
}
// 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
>
>
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)
);
}
template<class RET, class A, class B>
RET ret_call(A& a, B& b) const {
return inherited::template call<RET>(a, b, const_null_type());
}
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
@@ -219,6 +244,55 @@ public:
return inherited::template call<RET>(a, b, c);
}
// 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
>
>
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)
);
}
// 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
>
>
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)
);
}
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
@@ -251,6 +325,82 @@ public:
};
// This subclass adds lambda functors the ability to be copied,
// if the functors are 'copy compatible'
// This ability is needed, if lambda functor evaluation results in
// a lambda functor (e.g. with protect).
template <class Act, class Args, int Code>
struct lambda_functor_sub<lambda_functor_args<Act, Args, Code> >
: public lambda_functor<lambda_functor_args<Act, Args, Code> > {
// as long as action and arity are the same, lambda functors are convertible
// if the argument tuples are.
template <class Args2> lambda_functor_sub
(const lambda_functor<lambda_functor_args<Act, Args2, Code> >& f)
: lambda_functor<lambda_functor_args<Act, Args, Code> >(f.args) {}
};
// any lambda functor can turned into const_incorrect_lambda_functor
// The opreator() takes arguments as consts and then casts constness
// away. So this breaks const correctness!!! but is a necessary workaround
// in some cases due to language limitations.
// Note, that this is not a lambda_functor anymore, so it can not be used
// as a sub lambda expression.
template <class Arg>
struct const_incorrect_lambda_functor
: private lambda_functor<Arg> {
public:
BOOST_STATIC_ASSERT(dig_arity<Arg>::value <= THIRD);
// only allowed for normal lambda functions, not EXCEPTION ones
typedef lambda_functor<Arg> inherited;
explicit const_incorrect_lambda_functor(const lambda_functor<Arg>& lf)
: inherited(lf.args) {}
// This is provided just for completeness; no arguments, no constness
// problems.
typename return_type<inherited,
open_args<null_type, null_type, null_type> >::type
operator()() const
{
return inherited::template ret_call<
typename return_type<
inherited,
open_args<null_type, null_type, null_type>
>::type>();
}
template<class A>
typename return_type<inherited, open_args<A&, null_type, null_type> >::type
operator()(const A& a) const
{
return inherited::template ret_call<
typename return_type<inherited, open_args<A&, null_type, null_type>
>::type>(const_cast<A&>(a));
}
template<class A, class B>
typename return_type<inherited, open_args<A&, B&, null_type> >::type
operator()(const A& a, const B& b) const
{
return inherited::template ret_call<
typename return_type<inherited, open_args<A&, B&, null_type>
>::type>(const_cast<A&>(a), const_cast<B&>(b));
}
template<class A, class B, class C>
typename return_type<inherited, open_args<A&, B&, C&> >::type
operator()(const A& a, const B& b, const C& c) const
{
return inherited::template ret_call<
typename return_type<inherited, open_args<A&, B&, C&>
>::type>(const_cast<A&>(a), const_cast<B&>(b), const_cast<C&>(c));
}
};
// -- free variables types --------------------------------------------------
template <int I> class placeholder {};

View File

@@ -43,6 +43,9 @@ template <int I, class Act> class action;
template <class BinderArgs>
struct lambda_functor;
template <class BinderArgs>
struct lambda_functor_sub;
template <class Action,
class Args,
int ArityCode>

View File

@@ -147,6 +147,12 @@ template <class T> struct is_lambda_functor_ {
template <class Arg> struct is_lambda_functor_<lambda_functor<Arg> > {
BOOST_STATIC_CONSTANT(bool, value = true);
};
// lambda_functor_sub goes for lambda functor as well
template <class Arg> struct is_lambda_functor_<lambda_functor_sub<Arg> > {
BOOST_STATIC_CONSTANT(bool, value = true);
};
} // end detail

View File

@@ -29,6 +29,7 @@ namespace lambda {
// Specialization for comma.
template<class Args>
class lambda_functor_base<action<2, other_action<comma_action> >, Args> {
public:
Args args;
public:
explicit lambda_functor_base(const Args& a) : args(a) {}
@@ -43,6 +44,7 @@ public:
// Specialization for logical and (to preserve shortcircuiting)
template<class Args>
class lambda_functor_base<action<2, logical_action<and_action> >, Args> {
public:
Args args;
public:
explicit lambda_functor_base(const Args& a) : args(a) {}
@@ -57,6 +59,7 @@ public:
// Specialization for logical or (to preserve shortcircuiting)
template<class Args>
class lambda_functor_base<action<2, logical_action< or_action> >, Args> {
public:
Args args;
public:
explicit lambda_functor_base(const Args& a) : args(a) {}

View File

@@ -45,6 +45,10 @@ ret(const lambda_functor<Arg>& a1)
// protect ------------------
// protecting others than lambda functors has no effect
template <class T>
inline const T& protect(const T& t) { return t; }
template<class Arg>
inline const
lambda_functor<
@@ -66,7 +70,6 @@ protect(const lambda_functor<Arg>& a1)
(tuple<lambda_functor<Arg> >(a1));
}
// -- identity -------------------------
// identity templates
template<class Arg>
@@ -143,8 +146,78 @@ public:
> type;
};
// -------------------------------------------------------------------
// Hides the lambda functorness of a lambda functor.
// After this, the functor is immune to argument substitution, etc.
// This can be used, e.g. to make it safe to pass lambda functors as
// arguments to functions, which might use them as target functions
// note, unlambda and protect are different things. Protect hides the lambda
// functor for one application, unlambda for good.
template <class Arg>
class non_lambda_functor {
lambda_functor<Arg> lf; // a lambda functor
public:
// This functor defines the result_type typedef.
// 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;
non_lambda_functor(const lambda_functor<Arg>& a) : lf(a) {}
result_type operator()() const {
return lf.template ret_call<result_type>();
}
template<class A>
result_type operator()(A& a) const {
return lf.template ret_call<result_type>(a);
}
template<class A, class B>
result_type operator()(A& a, B& b) const {
return lf.template ret_call<result_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);
}
};
template <class Arg>
inline const Arg& unlambda(const Arg& a) { return a; }
template <class Arg>
inline const non_lambda_functor<Arg> unlambda(const lambda_functor<Arg>& a)
{
return non_lambda_functor<Arg>(a);
};
// Due to a language restriction, lambda functors cannot be made to
// accept non-const rvalue arguments. Usually iterators do not return
// temporaries, but sometimes they do. That's why a workaround is provided.
// Note, that this potentially breaks const correctness, so be careful!
template <class Arg>
inline const const_incorrect_lambda_functor<Arg>
break_const(const lambda_functor<Arg>& lf)
{
return const_incorrect_lambda_functor<Arg>(lf);
}
} // namespace lambda
} // namespace boost
#endif

View File

@@ -149,6 +149,7 @@ lambda_functor_base<
Args
>
{
public:
Args args;
public:
explicit lambda_functor_base(const Args& a) : args(a) {}
@@ -334,7 +335,8 @@ lambda_functor_base< \
>, \
Args \
> \
{ \
{ \
public: \
Args args; \
public: \
explicit lambda_functor_base(const Args& a) : args(a) {} \
@@ -370,6 +372,7 @@ lambda_functor_base< \
Args \
> \
{ \
public: \
Args args; \
public: \
explicit lambda_functor_base(const Args& a) : args(a) {} \