1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<!-- Copyright Aleksey Gurtovoy 2006. 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) -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.3.6: http://docutils.sourceforge.net/" />
<title>THE BOOST MPL LIBRARY: Higher-Order Metafunctions</title>
<link rel="stylesheet" href="../style.css" type="text/css" />
</head>
<body class="docframe">
<table class="header"><tr class="header"><td class="header-group navigation-bar"><span class="navigation-group"><a href="./implementing-division.html" class="navigation-link">Prev</a> <a href="./handling-placeholders.html" class="navigation-link">Next</a></span><span class="navigation-group-separator"> | </span><span class="navigation-group"><a href="./dimensional-analysis.html" class="navigation-link">Back</a> <a href="./handling-placeholders.html" class="navigation-link">Along</a></span><span class="navigation-group-separator"> | </span><span class="navigation-group"><a href="./tutorial-metafunctions.html" class="navigation-link">Up</a> <a href="../index.html" class="navigation-link">Home</a></span><span class="navigation-group-separator"> | </span><span class="navigation-group"><a href="./tutorial_toc.html" class="navigation-link">Full TOC</a></span></td>
<td class="header-group page-location"><a href="../index.html" class="navigation-link">Front Page</a> / <a href="./tutorial-metafunctions.html" class="navigation-link">Tutorial: Metafunctions and Higher-Order Metaprogramming</a> / <a href="./higher-order.html" class="navigation-link">Higher-Order Metafunctions</a></td>
</tr></table><div class="header-separator"></div>
<div class="section" id="higher-order">
<h1><a class="toc-backref" href="./tutorial-metafunctions.html#id47" name="higher-order">Higher-Order Metafunctions</a></h1>
<p>In the previous section we used two different forms —
metafunction classes and placeholder expressions —
to pass and return metafunctions just like any other metadata.
Bundling metafunctions into "first class metadata" allows
<tt class="literal"><span class="pre">transform</span></tt> to perform an infinite variety of different
operations: in our case, multiplication and division of dimensions.
Though the idea of using functions to manipulate other functions
may seem simple, its great power and flexibility <a class="citation-reference" href="#hudak89" id="id9" name="id9">[Hudak89]</a> has
earned it a fancy title: <strong>higher-order functional programming</strong>.
A function that operates on another function is known as a
<strong>higher-order function</strong>. It follows that <tt class="literal"><span class="pre">transform</span></tt> is a
higher-order
metafunction: a metafunction that operates on another metafunction.</p>
<table class="citation" frame="void" id="hudak89" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id9" name="hudak89">[Hudak89]</a></td><td>Paul Hudak. "Conception, Evolution, and Application of
Functional Programming Languages," ACM Computing Surveys 21,
no. 3 Pages: 359 - 411. New York: ACM Press. 1989.
ISSN:0360-0300. http://doi.acm.org/10.1145/72551.72554.</td></tr>
</tbody>
</table>
<p>Now that we've seen the power of higher-order metafunctions at
work, it would be good to be able to create new ones. In order to
explore the basic mechanisms, let's try a simple example. Our task
is to write a metafunction called <tt class="literal"><span class="pre">twice</span></tt>, which — given a unary
metafunction <em>f</em> and arbitrary metadata <em>x</em> — computes:</p>
<blockquote>
<em>twice</em>(<em>f</em>, <em>x</em>) := <em>f</em>(<em>f</em>(<em>x</em>))</blockquote>
<p>This might seem like a trivial example, and in fact it is. You
won't find much use for <tt class="literal"><span class="pre">twice</span></tt> in real code. We hope you'll
bear with us anyway: Because it doesn't do much more than accept
and invoke a metafunction, <tt class="literal"><span class="pre">twice</span></tt> captures all the essential
elements of "higher-orderness" without any distracting details.</p>
<p>If <em>f</em> is a metafunction class, the definition of <tt class="literal"><span class="pre">twice</span></tt> is
straightforward:</p>
<pre class="literal-block">
template <class F, class X>
struct twice
{
typedef typename F::template apply<X>::type once; // f(x)
typedef typename F::template apply<once>::type type; // f(f(x))
};
</pre>
<!-- @ prefix.append(
'''#include <boost/type_traits/add_pointer.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>''')
twice_test = '''
#include <boost/mpl/assert.hpp>
struct add_pointer_f
{
template <class T> struct apply : boost::add_pointer<T>
{};
};
BOOST_MPL_ASSERT((boost::is_same<twice<add_pointer_f,int>::type,int**>));
'''
example.append(twice_test)
compile() -->
<!-- @litre_translator.line_offset -= 7 -->
<p>Or, applying metafunction forwarding:</p>
<pre class="literal-block">
template <class F, class X>
struct twice
: F::template apply<
typename F::template apply<X>::type
>
{};
</pre>
<!-- @ example.append(twice_test)
compile() -->
<div class="admonition-c-language-note admonition">
<p class="admonition-title first">C++ Language Note</p>
<p>The C++ standard requires the <tt class="literal"><span class="pre">template</span></tt> keyword when we use a
<strong>dependent name</strong> that refers to a member template.
<tt class="literal"><span class="pre">F::apply</span></tt> may or may not name a template, <em>depending</em> on the
particular <tt class="literal"><span class="pre">F</span></tt> that is passed. See <a class="reference" href="./resources.html">the book's</a> Appendix B for more
information about <tt class="literal"><span class="pre">template</span></tt>.</p>
</div>
<p>Given the need to sprinkle our code with the <tt class="literal"><span class="pre">template</span></tt> keyword,
it would be nice to reduce the syntactic burden of invoking
metafunction classes. As usual, the solution is to factor the
pattern into a metafunction:</p>
<pre class="literal-block">
template <class UnaryMetaFunctionClass, class Arg>
struct apply1
: UnaryMetaFunctionClass::template apply<Arg>
{};
</pre>
<p>Now <tt class="literal"><span class="pre">twice</span></tt> is just:</p>
<pre class="literal-block">
template <class F, class X>
struct twice
: apply1<F, typename apply1<F,X>::type>
{};
</pre>
<p>To see <tt class="literal"><span class="pre">twice</span></tt> at work, we can apply it to a little metafunction
class built around the <tt class="literal"><span class="pre">add_pointer</span></tt> metafunction:</p>
<pre class="literal-block">
struct add_pointer_f
{
template <class T>
struct apply : boost::add_pointer<T> {};
};
</pre>
<!-- @litre_translator.line_offset -= 7 -->
<p>Now we can use <tt class="literal"><span class="pre">twice</span></tt> with <tt class="literal"><span class="pre">add_pointer_f</span></tt> to build
pointers-to-pointers:</p>
<pre class="literal-block">
BOOST_STATIC_ASSERT((
boost::is_same<
twice<add_pointer_f, int>::type
, int**
>::value
));
</pre>
<!-- @ apply1 = stack[-4]
add_pointer_f = stack[-2]
compile('all', pop = 0) -->
</div>
<div class="footer-separator"></div>
<table class="footer"><tr class="footer"><td class="header-group navigation-bar"><span class="navigation-group"><a href="./implementing-division.html" class="navigation-link">Prev</a> <a href="./handling-placeholders.html" class="navigation-link">Next</a></span><span class="navigation-group-separator"> | </span><span class="navigation-group"><a href="./dimensional-analysis.html" class="navigation-link">Back</a> <a href="./handling-placeholders.html" class="navigation-link">Along</a></span><span class="navigation-group-separator"> | </span><span class="navigation-group"><a href="./tutorial-metafunctions.html" class="navigation-link">Up</a> <a href="../index.html" class="navigation-link">Home</a></span><span class="navigation-group-separator"> | </span><span class="navigation-group"><a href="./tutorial_toc.html" class="navigation-link">Full TOC</a></span></td>
</tr></table></body>
</html>
|