Boost logoBoost.Flyweight Tutorial Annex: MPL lambda expressions



This short introduction to lambda expressions is meant for readers unfamiliar with the Boost MPL Library who want to rapidly acquire a working knowledge of the basic concepts for the purposes of using them in Boost.Flyweight. Please refer to the Boost.MPL documentation for further information beyond these introductory notes.

The specifiers defined by Boost.Flyweight rely heavily on the Lambda Expression concept defined by the Boost MPL Library. A lambda expression can be thought of as a compile-time "type function", an entity (a concrete type, actually) that can be invoked with a list of types and returns some associated type in its turn. Consider for instance an arbitrary class template:

template<typename T,typename Q>
class foo
{
  ...
};

and suppose we want to have a lambda expression that, when invoked with some generic types Arg1 and Arg2, returns foo<Arg1,Arg2>. Such a lambda expression can be implemented in two ways

  1. As a MPL Metafunction Class, a type with a special nested class template named apply:
    struct foo_specifier
    {
      template<typename Arg1,typename Arg2>
      struct apply
      {
        // this is the "return type" of foo_specifier
        typedef foo<Arg1,Arg2> type;
      };
    };
    
  2. As a MPL Placeholder Expression, a class template instantiated with one or more placeholders:
    typedef foo<boost::mpl::_1,boost::mpl::_2> foo_specifier;
    
    Note that, in this case, foo_specifier is a concrete type, much as int or std::set<std::string> are; yet, MPL internal mechanisms are able to detect that this type has been gotten from instantiating a class template with placeholders boost::mpl::_1 and boost::mpl::_2 and take these placeholders as slots to be substituted for actual types (the first and second type supplied, respectively) when foo_specifier is invoked. So, an instantiation of foo can be used to refer back to the foo class template itself! The net effect is the same as with metafunctions, but placeholder expressions spare us the need to write boilerplate metafunction classes --and the kind of metaprogramming magic they depend on has an undeniable beauty to it.
So far the examples shown just forward the arguments Arg1 and Arg2 directly to a class template without further elaboration, but there is nothing preventing us from doing some argument manipulation, like, for instance, switching their places:

struct foo_specifier
{
  template<typename Arg1,typename Arg2>
  struct apply{typedef foo<Arg2,Arg1> type;};
};

typedef foo<boost::mpl::_2,boost::mpl::_1> foo_specifier;

passing placeholder subexpressions as arguments to the overall expression:

struct foo_specifier
{
  template<typename Arg1,typename Arg2>
  struct apply{typedef foo<boost::shared_ptr<Arg1>,std::less<Arg2> > type;};
};

typedef foo<
  boost::shared_ptr<boost::mpl::_1>,
  std::less<boost::mpl::_2>
> foo_specifier;

or accepting less or more arguments than the class template itself (the number of parameters of a lambda expression is called its arity):

struct foo_specifier
{
  template<typename Arg1>
  struct apply{typedef foo<Arg1,std::less<Arg1> type;};
};

typedef foo<boost::mpl::_1,std::less<boost::mpl::_1> > foo_specifier;

struct foo_specifier
{
  template<typename Arg1,typename Arg2,typename Arg3>
  struct apply{typedef foo<Arg1,foo<Arg2,Arg3> > type;};
};

typedef foo<boost::mpl::_1,foo<boost::mpl::_2,boost::mpl::_3> > foo_specifier;



Revised August 13th 2008

© Copyright 2006-2008 Joaquín M López Muñoz. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)