now also able to close the last function argument
This commit is contained in:
parent
81d0e133c8
commit
67e5779d24
2 changed files with 47 additions and 20 deletions
|
|
@ -24,8 +24,17 @@
|
||||||
/** @file function-closure.hpp
|
/** @file function-closure.hpp
|
||||||
** Partial function application and building a complete function closure.
|
** Partial function application and building a complete function closure.
|
||||||
** This is a small addendum to (and thin wrapper for) tr1/functional, supporting
|
** This is a small addendum to (and thin wrapper for) tr1/functional, supporting
|
||||||
** the case when a function should be closed over (all) arguments, where especially
|
** the case when a function should be closed over (partially or all) arguments,
|
||||||
** the parameter values to close on are provided as a tuple.
|
** where especially the parameter values to close on are provided as a tuple.
|
||||||
|
**
|
||||||
|
** Because we have to deal with arbitrary functions and arbitrary parameter types,
|
||||||
|
** we need a lot of repetitive code to "catch" functions from zero to nine arguments.
|
||||||
|
** At the bottom of this header, you'll find a function-style interface, which
|
||||||
|
** wraps up all these technicalities.
|
||||||
|
**
|
||||||
|
** @todo the implementation is able to handle partial application with N arguments,
|
||||||
|
** but currently we need just one argument, thus only this case was wrapped
|
||||||
|
** up into a convenient functions func::applyFirst and func::applyLast
|
||||||
**
|
**
|
||||||
** @see control::CommandDef usage example
|
** @see control::CommandDef usage example
|
||||||
** @see function.hpp
|
** @see function.hpp
|
||||||
|
|
@ -363,23 +372,29 @@ namespace typelist{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ===== Helpers for partial function application ===== */
|
/* ===== Helpers for partial function application ===== */
|
||||||
|
|
||||||
using std::tr1::_Placeholder; // what is the "official" way to import them?
|
using std::tr1::_Placeholder; // what is the "official" way to import them?
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a sequence of tr1 function argument placeholder types.
|
||||||
|
* For each of the elements of the provided reference sequence,
|
||||||
|
* a Placeholder is added, numbers counting up starting with 1 (!)
|
||||||
|
*/
|
||||||
template<typename TYPES, uint i=0>
|
template<typename TYPES, uint i=0>
|
||||||
class PlaceholderTuple
|
class PlaceholderTuple
|
||||||
{
|
{
|
||||||
// typedef typename Tuple<TYPES>::HeadType HeadType;
|
|
||||||
// typedef typename Tuple<TYPES>::ArgList TypeList;
|
|
||||||
// typedef typename Tuple<TYPES>::Tail::ArgList TailList;
|
|
||||||
typedef typename Tuple<TYPES>::Type TypeSeq;
|
typedef typename Tuple<TYPES>::Type TypeSeq;
|
||||||
typedef typename Tuple<TYPES>::TailType TailSeq;
|
typedef typename Tuple<TYPES>::TailType TailSeq;
|
||||||
|
|
||||||
typedef typename PlaceholderTuple<TailSeq, i+1>::PlaceholderSeq TailPlaceholderSeq;
|
typedef typename PlaceholderTuple<TailSeq, i+1>::PlaceholderSeq TailPlaceholderSeq;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef typename Prepend<_Placeholder<i>, TailPlaceholderSeq>::Seq PlaceholderSeq;
|
typedef typename Prepend<_Placeholder<i+1>, TailPlaceholderSeq>::Seq PlaceholderSeq;
|
||||||
typedef Tuple<PlaceholderSeq> Type;
|
typedef Tuple<PlaceholderSeq> Type;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
@ -397,12 +412,12 @@ namespace typelist{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // (END) impl-namespace (func)
|
} // (END) impl-namespace (func)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ======= core operations: closures and partial application ========= */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closure-creating template.
|
* Closure-creating template.
|
||||||
* @note taking functor objects \em and parameters per reference
|
* @note taking functor objects \em and parameters per reference
|
||||||
|
|
@ -434,6 +449,7 @@ namespace typelist{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Partial function application
|
* Partial function application
|
||||||
* Takes a function and a value tuple,
|
* Takes a function and a value tuple,
|
||||||
|
|
@ -447,28 +463,38 @@ namespace typelist{
|
||||||
{
|
{
|
||||||
typedef typename func::_Fun<SIG>::Args Args;
|
typedef typename func::_Fun<SIG>::Args Args;
|
||||||
typedef typename func::_Fun<SIG>::Ret Ret;
|
typedef typename func::_Fun<SIG>::Ret Ret;
|
||||||
|
|
||||||
enum { ARG_CNT = count<typename Args::List>::value
|
|
||||||
, VAL_CNT = count<typename VAL::List>::value
|
|
||||||
, ROFFSET = (VAL_CNT < ARG_CNT)? ARG_CNT-VAL_CNT : 0
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef typename func::PlaceholderTuple<Args>::PlaceholderSeq::List Placeholders;
|
|
||||||
typedef typename Args::List ArgsList;
|
typedef typename Args::List ArgsList;
|
||||||
typedef typename VAL::List ValList;
|
typedef typename VAL::List ValList;
|
||||||
|
|
||||||
typedef typename Splice<Placeholders, ValList>::List LeftReplaced;
|
enum { ARG_CNT = count<ArgsList>::value
|
||||||
typedef typename Splice<Placeholders, ValList, ROFFSET>::List RightReplaced;
|
, VAL_CNT = count<ValList> ::value
|
||||||
|
, ROFFSET = (VAL_CNT < ARG_CNT)? ARG_CNT-VAL_CNT : 0
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// create list of the *remaining* arguments, after applying the ValList
|
||||||
typedef typename Splice<ArgsList, ValList>::Back LeftReduced;
|
typedef typename Splice<ArgsList, ValList>::Back LeftReduced;
|
||||||
typedef typename Splice<ArgsList, ValList, ROFFSET>::Front RightReduced;
|
typedef typename Splice<ArgsList, ValList, ROFFSET>::Front RightReduced;
|
||||||
|
|
||||||
|
// build a list, where each of the *remaining* arguments is replaced by a placeholder marker
|
||||||
|
typedef typename func::PlaceholderTuple<LeftReduced>::PlaceholderSeq::List LeftPlaceholders;
|
||||||
|
typedef typename func::PlaceholderTuple<RightReduced>::PlaceholderSeq::List RightPlaceholders;
|
||||||
|
|
||||||
|
// ... and splice these placeholders on top of the original argument type list,
|
||||||
|
// thus retaining the types to be closed, but setting a placeholder for each remaining argument
|
||||||
|
typedef typename Splice<ArgsList, LeftPlaceholders, VAL_CNT>::List LeftReplaced;
|
||||||
|
typedef typename Splice<ArgsList, RightPlaceholders, 0 >::List RightReplaced;
|
||||||
|
|
||||||
typedef Tuple<LeftReplaced> TupleL;
|
typedef Tuple<LeftReplaced> TupleL;
|
||||||
typedef Tuple<RightReplaced> TupleR;
|
typedef Tuple<RightReplaced> TupleR;
|
||||||
|
|
||||||
typedef typename Tuple<LeftReduced>::Type ArgsL;
|
typedef typename Tuple<LeftReduced>::Type ArgsL;
|
||||||
typedef typename Tuple<RightReduced>::Type ArgsR;
|
typedef typename Tuple<RightReduced>::Type ArgsR;
|
||||||
|
|
||||||
|
// create a "builder" helper, which accepts exactly the value tuple elements
|
||||||
|
// and puts them at the right location, while default-constructing the remaining
|
||||||
|
// (=placeholder)-arguments. Using this builder helper, we can finally set up
|
||||||
|
// the argument tuples (Left/RightReplacedArgs) used for the tr1::bind call
|
||||||
typedef tuple::BuildTuple<LeftReplaced, ValList> BuildL;
|
typedef tuple::BuildTuple<LeftReplaced, ValList> BuildL;
|
||||||
typedef tuple::BuildTuple<RightReplaced, ValList, ROFFSET> BuildR;
|
typedef tuple::BuildTuple<RightReplaced, ValList, ROFFSET> BuildR;
|
||||||
|
|
||||||
|
|
@ -498,6 +524,7 @@ namespace typelist{
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/** do a partial function application, closing the first arguments
|
/** do a partial function application, closing the first arguments
|
||||||
* f(a,b,c)->res + (a,b) yields f(c)->res
|
* f(a,b,c)->res + (a,b) yields f(c)->res
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -261,7 +261,7 @@ namespace test {
|
||||||
fun_23 = func::applyFirst (func123, Num<1>(19));
|
fun_23 = func::applyFirst (func123, Num<1>(19));
|
||||||
res = fun_23 (_2_,_3_).o_;
|
res = fun_23 (_2_,_3_).o_;
|
||||||
ASSERT (24 == res);
|
ASSERT (24 == res);
|
||||||
#if false //////////////TODO silly bug in the Split template!
|
|
||||||
typedef function<Num<1>(Num<1>, Num<2>)> F12;
|
typedef function<Num<1>(Num<1>, Num<2>)> F12;
|
||||||
F12 fun_12 = func::applyLast(f, Num<3>(20));
|
F12 fun_12 = func::applyLast(f, Num<3>(20));
|
||||||
res = fun_12 (_1_,_2_).o_;
|
res = fun_12 (_1_,_2_).o_;
|
||||||
|
|
@ -270,7 +270,7 @@ namespace test {
|
||||||
fun_12 = func::applyLast(func123, Num<3>(21));
|
fun_12 = func::applyLast(func123, Num<3>(21));
|
||||||
res = fun_12 (_1_,_2_).o_;
|
res = fun_12 (_1_,_2_).o_;
|
||||||
ASSERT (24 == res);
|
ASSERT (24 == res);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue