Boost logo

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