|
Boost : |
From: Aleksey Gurtovoy (alexy_at_[hidden])
Date: 2001-12-18 06:24:31
Peter Dimov wrote:
> > I think you should forget that term, but what Mat means
> > (and it's Mat's term, borrowed from lisp) is a class written
> > this way:
> >
> > struct my_metafunction
> > {
> > template <class Param1, ...class ParamN>
> > struct apply
> > {
> > ... // optional metacomputations here
> > typedef type-expression type; // return value
> > };
> > };
> >
> > A uniform interface to metafunctions makes it possible to
> > re-use them in different contexts. That's the metafunction
> > formulation used in MPL.
>
> Was this concept only introduced for portability reasons (BTW
> did you know that VC 7 supports template template parameters)
> or there is a deeper meaning? (I can see one difference right
> away but I'm interested in the design rationale.)
There were two reasons why representing metafunctions as class templates
didn't seem like a viable option at the time I made the decision:
1) class templates cannot be "returned" from other functions and algorithms
(because of the lack of template typedefs);
2) they cannot have "state" (because default template arguments affect the
class template "signature", e.g. you cannot pass 'template<typename T1,
typename T2, long Sum = 0> adder;' to an algorithm that takes
'template<typename T1, typename T2> BinaryOp')
The second reason was important at early times of MPL, when metafunctions
were allowed to combine state with behavior; for example, at that time
summing values in a sequence using mpl::for_each looked like this:
template<long S = 0>
struct adder
{
template<typename T> struct apply
{
typedef adder<T::value + S> type;
};
};
typedef mpl::value_range<0,10> values;
typedef mpl::for_each<values, adder>::function f;
BOOST_STATIC_ASSERT(f::value == 45);
Of course, as the library has evolved to a functional approach with
stateless metafunctions, this part of the original motivation has become a
non-issue.
At the same time, experience with inline function classes composition,
arguments binding, and partial implementation of compile-time lambda
facility made it clear that going down "function classes" route was a right
decision, in particular because it has promised to provide much more
readable composition syntax comparing to the binding of bare class
templates:
// using current MPL 'find' algorithm that takes a "function class" as
predicate
typedef mpl::find<
types
, mpl::logical_and<
mpl::logical_or<
boost::is_same<_1,int>
, boost::is_convertible<long,_1>
>
, mpl::greater< mpl::size_of<_1>, mpl::int_c<4> >
>
>::type itor;
// using hypothetical find that takes "unary class template
metufunction"
// (template<typename T> struct f); this is equivalent to the above code
typedef mpl::find<
types
, mpl::compose_f_gx_hy<
mpl::logical_and
, mpl::compose_f_gx_hy<
mpl::logical_or
, mpl::bind2nd<is_same, int>::type
, mpl::bind1st<is_convertible, long>::type
>::type
, mpl::compose_f_gx_y<
mpl::greater
, mpl::size_of
, mpl::int_c<4>
>::type
>::type
>::type itor;
Aleksey
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk