3. Lambda facility

The MPL's lambda facility allows the inline composition of class templates into ‘lambda expressions’, which are classes and can therefore be passed around as ordinary metafunction classes, or transformed into metafunction classes before application using the expression:

typedef mpl::lambda<expr>::type func;

For example, boost::remove_const traits template from Boost type_traits library [TTL] is a class template (obviously), or a metafunction in MPL terminology. The simplest example of an ‘inline composition’ of it would be something like:

typedef boost::remove_const<_1> expr;

This forms a so called ‘lambda expression’, which is neither a metafunction class, nor a metafunction, yet can be passed around everywhere because it's an ordinary C++ class, because all MPL facilities are polymorphic with respect to their arguments. Now, that lambda expression can be transformed into a metafunction class using the MPL's lambda facility:

typedef boost::remove_const<_1> expr;
typedef mpl::lambda<expr>::type func;

The func is a unary metafunction class and can be used as such. In particular, it can be pass around or invoked (applied):

typedef mpl::apply<func,int const>::type res;
BOOST_MPL_ASSERT_IS_SAME(res, int);

or even

typedef func::apply<int const>::type res;
BOOST_MPL_ASSERT_IS_SAME(res, int);

Inline composition is very appealing syntactically when one deals with metafunctions, because it makes the expression obvious:

typedef mpl::logical_or<
      mpl::less< mpl::size_of<_1>, mpl::int_c<16> >
    , boost::is_same<_1,_2>
    > expr;

typedef mpl::lambda<expr>::type func;

And one does not have to specify the last part (typedef lambda<expr>::type func), because all the algorithms do this to any of their metafunction class operands internally (a lambda<T>::type expression applied to a metafunction class gives back the same metafunction class, so it's safe to apply the expression unconditionally).

The alternative way to write an equivalent of the above metafunction class would be:

typedef bind<
      mpl::meta_fun2<mpl::logical_or>
    , mpl::bind< mpl::meta_fun2<mpl::less>
        , mpl::bind< mpl::meta_fun1<mpl::size_of>,_1 >
        , mpl::int_c<16>
        >
    , mpl::bind< mpl::meta_fun2<boost::is_same>,_1,_2 >
    > func;

Or to use mpl::compose_ family of templates in a similar way. Here, we use mpl::meta_fun templates to convert metafunctions into metafunction classes and then combine them using mpl::bind. The transformation from this form to the above inline lambda expression and vice-versa is mechanical, and that is essentially what the typedef mpl::lambda<expr>::type expression does.

For its own metafunctions (algorithms, primitives, etc.), MPL enables one to write the above in a less cumbersome way:

typedef mpl::bind<
      mpl::logical_or<>
    , mpl::bind< mpl::less<>, mpl::bind<mpl::size_of<>,_1>, mpl::int_c<16> >
    , mpl::bind< mpl::make_f2<boost::is_same>, _1,_2 >
    > func;

Note that we still have to wrap is_same into make_f2, because it's a foreign template.

Now, about combining class template metafunctions and metafunction classes in the single lambda expression - it can be done like this:

struct my_predicate
{
    template< typename T1, typename T2 > struct apply
    {
        //...
    };
};

typedef mpl::logical_or<
      mpl::less< mpl::size_of<_>,mpl::int_c<16> >
    , mpl::bind< my_predicate,_,_ > // here
    > expr;

To bind something to one of its arguments (or change the order of parameters), then use either:

typedef mpl::logical_or<
      mpl::less< mpl::size_of<_>,mpl::int_c<16> >
    , mpl::bind<my_predicate,int,_>::type // here
    > expr;

or

typedef mpl::logical_or<
      mpl::less< mpl::size_of<_>,mpl::int_c<16> >
    , my_predicate::apply<int,_> // here
    > expr;