<p>The MPL library is a C++ template metaprogramming framework of compile-time algorithms, sequences and metafunction classes. The two main documentation sources for the library is “the MPL paper”, and the library's reference documentation. If you haven't heard about the MPL before, we suggest you to start with the paper, and then move on to the reference documentation and the information in this document.</p>
<listyle="list-style-type: square">A. Gurtovoy, D. Abrahams, <ahref="./paper/html/index.html"target="_top">The Boost C++ Metaprogramming Library</a>, March 2002 | [<ahref="./paper/mpl_paper.pdf"target="_top">as .pdf</a>] [<ahref="./paper/mpl_paper.html"target="_top">as single .html</a>]</li>
<p>The latest library sources are available from the main trunk of the <ahref="http://www.boost.org/more/download.html#CVS"target="_top">Boost CVS</a>. <ahref="http://boost.sourceforge.net/release/">Boost 1.30.0 distribution</a> contains a stable version of the library as per March 12, 2003.</p>
<p>The examples used through this tutorial use fully qualified names, e.g. <tt>std::vector</tt> instead of plain <tt>vector</tt>. Any unqualified name refers to a local entity defined in the example itself. The names from <tt>boost::mpl</tt> namespace are referred to using <tt>mpl</tt> namespace alias (e.g. <tt>mpl::apply</tt> instead of <tt>boost::mpl::apply</tt>), as if the following namespace alias definition were in effect:</p>
<preclass="programlisting">
namespace mpl = boost::mpl;
</pre>
<p>Note that the library offers a special header, <tt>boost/mpl/alias.hpp</tt>, including which gives you a rough equivalent of the above. Alternatively, you can always spell the namespace alias definition manually in each translation unit as needed (if you choose to use the shorter namespace notation at all).</p>
<p>In MPL, the metaprogramming equivalent of a function is a <i>class template</i> containing a nested <tt>typedef</tt> member aptly named “type”:</p>
<preclass="programlisting">
// on the face of it, not very useful
template< typename T >
struct identity
{
typedef T type;
};
// perhaps more useful
template< typename T >
struct result_type
{
typedef typename T::result_type type;
};
</pre>
<p>“Invoking” a metafunction is as simple as instantiating the class template with particular template parameters (metafunction “arguments”) and accessing the result through the nested <tt>type</tt> member:</p>
<preclass="programlisting">
typedef identity<int>::type t1; // t1 == int
<p>The most interesting template metaprograms often contain a lot of decision-making code. Some of conditional decisions/behavior can be handled directly by (partial) class template specialization or function overloading <spanclass="citation">[<aclass="interlink"href="#ref.vel95a"title="[vel95a]">Vel95a</a>]</span>, <spanclass="citation">[<aclass="interlink"href="#ref.ale00"title="[ale00]">Ale00</a>]</span>, but in general there is a need for a standalone library primitive that would allow one to choose between two types basing on a compile-time expression. In <tt>boost::mpl</tt> such primitive is called <tt>if_</tt>:</p>
<p>Note that the first template parameter of the <tt>if_</tt> template is a type that should be a model of Integral Constant concept. The library also provides a less generic but sometimes more convenient form that accepts a condition in form of non-type <tt>bool</tt> template parameter:</p>
<p>In run-time C++, it is guaranteed that when we reach an <tt>if</tt> statement, only one branch will be executed. Executing the branch for which the result is not required would be unnecessary and inefficient. More importantly, frequently the non-required branch is invalid, and executing it would cause an error. For instance, the following code would be badly broken if both branches of the statement were evaluated:</p>
<preclass="programlisting">
void fun(giraffe* g)
{
if (g)
cout << g->name();
else
cout << "no giraffe";
}
</pre>
<p>In compile-time world, things are different. Which parameters to <tt>if_</tt> template are instantiated is determined by the form of each template parameter and the corresponding language rules (<spanclass="citation">[<aclass="interlink"href="#ref.iso98"title="[iso98]">ISO98</a>]</span>, section 14.7.1), not by the value of the compile-time expression being switched on. That means that if, in attempt to process a particular <tt>if_</tt> construct, the compiler determines that one of its “branch” template parameters is ill-formed, it will issue a diagnostics even if the value of compile-time expression would lead to “choosing” the other, valid parameter type.</p>
<p>To clarify what we just said, here is a broken first attempt at writing a <tt>pointed_type</tt> metafunction, that when instantiated for a <tt>T</tt> that is either a plain pointer or a smart pointer, “returns” the pointed type:</p>
<preclass="programlisting">
template< typename T >
struct pointed_type
{
typedef typename mpl::if_<
boost::is_pointer<T>
, typename boost::remove_pointer<T>::type
, typename T::element_type // #1
>::type type;
};
typedef pointed_type< std::auto_ptr<int>>::type int_ptr; // ok
typedef pointed_type<char*>::type char_ptr; // error in line #1!
</pre>
<p>If we try to compile the above, we will get something like this:</p>
<preclass="programlisting">
Error: name followed by "::" must be a class or namespace name
</pre>
<p>because the expression <tt>typename T::element_type</tt> is not valid in case of <tt>T == char*</tt>.</p>
<p>Here's what we need to do to make <tt>pointed_type</tt> work for plain pointers: <sup><aname="idakqwr"href="#ftn.IDAKQWR">1</a></sup> instead of instantiating our two potential results before passing them to <tt>if_</tt>, we need to write metafunctions that can be used to instantiate the results; then we can use <tt>if_</tt> to choose a metafunction, and only then should we use that function to get the result.</p>
<p><tt>boost::remove_pointer</tt> already is a metafunction. We just need to write an auxiliary function to return the <tt>element_type</tt> of a pointer type:</p>
<preclass="programlisting">
namespace aux {
template< typename T >
struct element_type
{
typedef typename T::element_type type;
};
}
</pre>
<p>Now we can select the metafunction to call based on the result of <tt>boost::is_pointer</tt>, and then <spanclass="emphasis"><em>apply</em></span> it to form the result:</p>
<preclass="programlisting">
template< typename T >
struct pointed_type
{
private:
// pick a metafunction
typedef typename mpl::if_<
boost::is_pointer<T>
, boost::remove_pointer<T>
, aux::element_type<T>
>::type func_; // #1
public:
// apply the metafunction
typedef typename func_::type type;
};
</pre>
<p>The key knowledge that makes the above viable is that in line #1 the compiler is <spanclass="emphasis"><em>guaranteed</em></span> not to instantiate <tt>boost::remove_pointer<T></tt> and <tt>aux::element_type<T></tt> templates, - even although they are passed as actual arguments to the <tt>if_</tt>.</p>
<p>The described technique is so common in template metaprograms, that it makes sense to facilitate the selection of the nested <tt>type</tt> member by introducing a high level equivalent to <tt>if_</tt> that will do <tt>func_::type</tt> operation as a part of its invocation. The MPL provides such a template - it's called <tt>apply_if</tt>. Using it, we can re-write the above code as simply as:</p>
<preclass="programlisting">
[
template< typename T >
struct pointed_type
{
typedef typename mpl::apply_if<
boost::is_pointer<T>
, boost::remove_pointer<T>
, aux::element_type<T>
>::type type;
};
</pre>
</div>
<divclass="section">
<divclass="titlepage">
<div>
<h3class="title"><aname="applyif2"></a>3.5. apply_if, part 2</h3>
</div>
</div>
<p>Besides solving the “making the code compile” problem, the <tt>apply_if</tt> technique we've just learned can be also used to improve metaprogram efficiency.</p>
<p>Suppose we want to define a high-level wrapper around <tt>boost::remove_pointer</tt> traits template, which will strip the pointer qualification conditionally. We will call it <tt>remove_pointer_if</tt>:</p>
<preclass="programlisting">
template<
typename Condition
, typename T
>
struct remove_pointer_if
{
typedef typename mpl::if_<
Condition
, typename boost::remove_pointer<T>::type
, T
>::type type;
};
</pre>
<p>The above works the first time, but it's not the most optimal implementation. Similar to our previous examples, <tt>boost::remove_pointer<T></tt> gets instantiated even if its result is never used. In the metaprogramming world compilation time is an important resource <spanclass="citation">[<aclass="interlink"href="#ref.abr01"title="[abr01]">Abr01</a>]</span>, and it is wasted by unnecessary template instantiations.</p>
<p>Let's see what we need to substitute <tt>if_</tt> by <tt>apply_if</tt> here. We already have one metafunction to pass to <tt>apply_if</tt> - <tt>boost::remove_pointer<T></tt>, but we need a second one, - let's call it <tt>f</tt>, - such as <tt>f<T>::type == T</tt>. We could write this one ourselves, but fortunately MPL already provides us with a template that matches this exact definition - it's called <tt>identity</tt>. Applying this knowledge, we get:</p>
<p>The library provides you with a fine-grained header structure with one header per public component (class/function template), with the header named after the component; for example, <tt>boost::mpl::apply<></tt> template is defined in the header <tt>boost/mpl/apply.hpp</tt>. This scheme both ensures that you don't pay for what you don't use in terms of compilation time/header dependencies, and frees you from memorizing/looking up header/component correspondence. Several composite headers for the entities that are likely to be used together (e.g. logical operations - <tt>logical_or</tt>, <tt>logical_and</tt>, etc.) are also provided. It allows one to avoid the burden of spelling many <tt>#include</tt> directives in programs that make an intensive use of the library facilities. <sup><aname="note.headers"href="#ftn.note.headers">2</a></sup></p>
<p>Besides <tt>boost/config.hpp</tt> header, the MPL heavily depends on two other Boost libraries - the Boost Preprocessor library <spanclass="citation">[<aclass="interlink"href="#ref.pre"title="[pre]">PRE</a>]</span>, and the Type Traits library <spanclass="citation">[<aclass="interlink"href="#ref.ttl"title="[ttl]">TTL</a>]</span>. These dependencies are essential and cannot be eliminated. In addition to those, the <tt>boost/mpl/assert.hpp</tt> header depends on Boost Static Assert library <spanclass="citation">[<aclass="interlink"href="#ref.sal"title="[sal]">SAL</a>]</span>. The library tests and examples may depend on some additional Boost libraries, e.g. Boost Bind <spanclass="citation">[<aclass="interlink"href="#ref.bbl"title="[bbl]">BBL</a>]</span>; you don't have to have those unless you are interested in actually compiling the tests/examples (probably you are, though).</p>
<listyle="list-style-type: square">Borland C++ 5.5.1</li>
</ul>
</div>
<p>An incomplete matrix of recent test compilation results is available from here - <ahref="http://www.mywikinet.com/mpl/log.html"target="_top">http://www.mywikinet.com/mpl/log.html</a>.</p>
<p>Following is a list of people who in one or another way contributed to the library development. The list is work in progress!</p>
<p>David Abrahams, Emily Winch, Eric Friedman, Vesa Karvonen, Peter Dimov, Mat Marcus, Fernando Cacciola, Paul Mensonides, David B. Held, John Bandela, Arnaldur Gylfason, Hamish Mackenzie.</p>
<p>[Abr01] <spanclass="authorgroup">David Abrahams and Carlos Pinto Coelho,</span><spanclass="title"><i><ahref="http://users.rcn.com/abrahams/instantiation_speed/index.html"target="_top">Effects of Metaprogramming Style on Compilation Time</a></i>,</span><spanclass="date">2001</span></p>
</div>
<divclass="biblioentry"><aname="ref.ale00"></a>
<p>[Ale00] <spanclass="author">Andrei Alexandrescu,</span><spanclass="title"><i><ahref="http://www.cuj.com/experts/1810/alexandr.htm"target="_top">On Conversions between Types and Values</a></i>,</span><spanclass="publishername">C/C++ Users Journal,</span><spanclass="date">October 2000</span></p>
<p>[TTL] <spanclass="title"><i>Boost Type Traits library</i>,</span><spanclass="bibliomisc"><ahref="http://www.boost.org/libs/type_traits/"target="_top">http://www.boost.org/libs/type_traits/</a></span></p>
<p><sup><aname="ftn.idakqwr"href="#IDAKQWR">1</a></sup> It would be easy to implement <tt>pointed_type</tt> using partial specialization to distinguish the case where <tt>T</tt> is a pointer. <tt>if_</tt> is used here to avoid creating a complicated example.</p>
<p><sup><aname="ftn.note.headers"href="#note.headers">2</a></sup> The Boost Preprocessor library <spanclass="citation">[<aclass="interlink"href="#ref.pre"title="[pre]">PRE</a>]</span> exposes a very similar physical organization; in fact, the libraries even share the common subdirectory naming (<tt>mpl/arithmetic</tt><-><tt>preprocessor/arithmetic</tt>, <tt>mpl/comparison</tt><-><tt>preprocessor/comparison</tt>, etc.).</p>