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
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; }; };
MPL
Placeholder Expression
, a class template instantiated with one or
more placeholders:
Note that, in this case,typedef foo<boost::mpl::_1,boost::mpl::_2> foo_specifier;
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.
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)