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 >