2004-11-28 03:35:12 +00:00
<?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" >
2007-11-03 03:25:13 +00:00
<!-- 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) -->
2004-11-28 03:35:12 +00:00
< 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 >