| <html> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> |
| <title>Users' Guide</title> |
| <link rel="stylesheet" href="../../../doc/src/boostbook.css" type="text/css"> |
| <meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> |
| <link rel="home" href="../index.html" title="The Boost C++ Libraries BoostBook Documentation Subset"> |
| <link rel="up" href="../proto.html" title="Chapter 16. Boost.Proto"> |
| <link rel="prev" href="../proto.html" title="Chapter 16. Boost.Proto"> |
| <link rel="next" href="reference.html" title="Reference"> |
| </head> |
| <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> |
| <table cellpadding="2" width="100%"><tr> |
| <td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../boost.png"></td> |
| <td align="center"><a href="../../../index.html">Home</a></td> |
| <td align="center"><a href="../../../libs/libraries.htm">Libraries</a></td> |
| <td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> |
| <td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> |
| <td align="center"><a href="../../../more/index.htm">More</a></td> |
| </tr></table> |
| <hr> |
| <div class="spirit-nav"> |
| <a accesskey="p" href="../proto.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../proto.html"><img src="../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="reference.html"><img src="../../../doc/src/images/next.png" alt="Next"></a> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h2 class="title" style="clear: both"> |
| <a name="proto.users_guide"></a><a class="link" href="users_guide.html" title="Users' Guide">Users' Guide</a> |
| </h2></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.getting_started">Getting Started</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.front_end">Fronts Ends: Defining |
| Terminals and Non-Terminals of Your DSEL</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.intermediate_form">Intermediate |
| Form: Understanding and Introspecting Expressions</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end">Back Ends: Making Expression |
| Templates Do Useful Work</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.examples">Examples</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.resources">Background and Resources</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.glossary">Glossary</a></span></dt> |
| </dl></div> |
| <a name="proto.users_guide.compilers__compiler_construction_toolkits__and_proto"></a><h4> |
| <a name="proto.users_guide.compilers__compiler_construction_toolkits__and_proto-heading"></a> |
| <a class="link" href="users_guide.html#proto.users_guide.compilers__compiler_construction_toolkits__and_proto">Compilers, |
| Compiler Construction Toolkits, and Proto</a> |
| </h4> |
| <p> |
| Most compilers have front ends and back ends. The front end parses the text |
| of an input program into some intermediate form like an abstract syntax tree, |
| and the back end takes the intermediate form and generates an executable from |
| it. |
| </p> |
| <p> |
| A library built with Proto is essentially a compiler for a domain-specific |
| embedded language (DSEL). It also has a front end, an intermediate form, and |
| a back end. The front end is comprised of the symbols (a.k.a., terminals), |
| members, operators and functions that make up the user-visible aspects of the |
| DSEL. The back end is made of evaluation contexts and transforms that give |
| meaning and behavior to the expression templates generated by the front end. |
| In between is the intermediate form: the expression template itself, which |
| is an abstract syntax tree in a very real sense. |
| </p> |
| <p> |
| To build a library with Proto, you will first decide what your interface will |
| be; that is, you'll design a programming language for your domain and build |
| the front end with tools provided by Proto. Then you'll design the back end |
| by writing evaluation contexts and/or transforms that accept expression templates |
| and do interesting things with them. |
| </p> |
| <p> |
| This users' guide is organized as follows. After a <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started" title="Getting Started">Getting |
| Started guide</a>, we'll cover the tools Proto provides for defining and |
| manipulating the three major parts of a compiler: |
| </p> |
| <div class="variablelist"> |
| <p class="title"><b></b></p> |
| <dl> |
| <dt><span class="term"><a class="link" href="users_guide.html#boost_proto.users_guide.front_end" title="Fronts Ends: Defining Terminals and Non-Terminals of Your DSEL">Front Ends</a></span></dt> |
| <dd><p> |
| How to define the aspects of your DSEL with which your users will interact |
| directly. |
| </p></dd> |
| <dt><span class="term"><a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form" title="Intermediate Form: Understanding and Introspecting Expressions">Intermediate |
| Form</a></span></dt> |
| <dd><p> |
| What Proto expression templates look like, how to discover their structure |
| and access their constituents. |
| </p></dd> |
| <dt><span class="term"><a class="link" href="users_guide.html#boost_proto.users_guide.back_end" title="Back Ends: Making Expression Templates Do Useful Work">Back Ends</a></span></dt> |
| <dd><p> |
| How to define evaluation contexts and transforms that make expression |
| templates do interesting things. |
| </p></dd> |
| </dl> |
| </div> |
| <p> |
| After that, you may be interested in seeing some <a class="link" href="users_guide.html#boost_proto.users_guide.examples" title="Examples">Examples</a> |
| to get a better idea of how the pieces all fit together. |
| </p> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="boost_proto.users_guide.getting_started"></a><a class="link" href="users_guide.html#boost_proto.users_guide.getting_started" title="Getting Started">Getting Started</a> |
| </h3></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.getting_started.installing_proto">Installing |
| Proto</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.getting_started.naming">Naming |
| Conventions</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.getting_started.hello_world">Hello |
| World</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.getting_started.hello_calculator">Hello |
| Calculator</a></span></dt> |
| </dl></div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.getting_started.installing_proto"></a><a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.installing_proto" title="Installing Proto">Installing |
| Proto</a> |
| </h4></div></div></div> |
| <a name="boost_proto.users_guide.getting_started.installing_proto.getting_proto"></a><h6> |
| <a name="boost_proto.users_guide.getting_started.installing_proto.getting_proto-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.installing_proto.getting_proto">Getting |
| Proto</a> |
| </h6> |
| <p> |
| You can get Proto by downloading Boost (Proto is in version 1.37 and later), |
| or by accessing Boost's SVN repository on SourceForge.net. Just go to |
| <a href="http://svn.boost.org/trac/boost/wiki/BoostSubversion" target="_top">http://svn.boost.org/trac/boost/wiki/BoostSubversion</a> |
| and follow the instructions there for anonymous SVN access. |
| </p> |
| <a name="boost_proto.users_guide.getting_started.installing_proto.building_with_proto"></a><h6> |
| <a name="boost_proto.users_guide.getting_started.installing_proto.building_with_proto-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.installing_proto.building_with_proto">Building |
| with Proto</a> |
| </h6> |
| <p> |
| Proto is a header-only template library, which means you don't need to |
| alter your build scripts or link to any separate lib file to use it. All |
| you need to do is <code class="computeroutput"><span class="preprocessor">#include</span> |
| <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">proto</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span></code>. Or, you might decide to just include |
| the core of Proto (<code class="computeroutput"><span class="preprocessor">#include</span> |
| <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span></code>) and whichever contexts and transforms |
| you happen to use. |
| </p> |
| <a name="boost_proto.users_guide.getting_started.installing_proto.requirements"></a><h6> |
| <a name="boost_proto.users_guide.getting_started.installing_proto.requirements-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.installing_proto.requirements">Requirements</a> |
| </h6> |
| <p> |
| Proto depends on Boost. You must use either Boost version 1.34.1 or higher, |
| or the version in SVN trunk. |
| </p> |
| <a name="boost_proto.users_guide.getting_started.installing_proto.supported_compilers"></a><h6> |
| <a name="boost_proto.users_guide.getting_started.installing_proto.supported_compilers-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.installing_proto.supported_compilers">Supported |
| Compilers</a> |
| </h6> |
| <p> |
| Currently, Boost.Proto is known to work on the following compilers: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"> |
| <li class="listitem"> |
| Visual C++ 7.1 and higher |
| </li> |
| <li class="listitem"> |
| GNU C++ 3.4 and higher |
| </li> |
| <li class="listitem"> |
| Intel on Linux 8.1 and higher |
| </li> |
| <li class="listitem"> |
| Intel on Windows 9.1 and higher |
| </li> |
| </ul></div> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| Please send any questions, comments and bug reports to eric <at> |
| boostpro <dot> com. |
| </p></td></tr> |
| </table></div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.getting_started.naming"></a><a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.naming" title="Naming Conventions">Naming |
| Conventions</a> |
| </h4></div></div></div> |
| <p> |
| Proto is a large library and probably quite unlike any library you've used |
| before. Proto uses some consistent naming conventions to make it easier |
| to navigate, and they're described below. |
| </p> |
| <a name="boost_proto.users_guide.getting_started.naming.functions"></a><h6> |
| <a name="boost_proto.users_guide.getting_started.naming.functions-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.naming.functions">Functions</a> |
| </h6> |
| <p> |
| All of Proto's functions are defined in the <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span></code> |
| namespace. For example, there is a function called <code class="computeroutput"><span class="identifier">value</span><span class="special">()</span></code> defined in <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span></code> |
| that accepts a terminal expression and returns the terminal's value. |
| </p> |
| <a name="boost_proto.users_guide.getting_started.naming.metafunctions"></a><h6> |
| <a name="boost_proto.users_guide.getting_started.naming.metafunctions-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.naming.metafunctions">Metafunctions</a> |
| </h6> |
| <p> |
| Proto defines <span class="emphasis"><em>metafunctions</em></span> that correspond to each |
| of Proto's free functions. The metafunctions are used to compute the functions' |
| return types. All of Proto's metafunctions live in the <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span></code> |
| namespace and have the same name as the functions to which they correspond. |
| For instance, there is a class template <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">value</span><span class="special"><></span></code> that you can use to compute the |
| return type of the <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">value</span><span class="special">()</span></code> function. |
| </p> |
| <a name="boost_proto.users_guide.getting_started.naming.function_objects"></a><h6> |
| <a name="boost_proto.users_guide.getting_started.naming.function_objects-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.naming.function_objects">Function |
| Objects</a> |
| </h6> |
| <p> |
| Proto defines <span class="emphasis"><em>function object</em></span> equivalents of all of |
| its free functions. (A function object is an instance of a class type that |
| defines an <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code> |
| member function.) All of Proto's function object types are defined in the |
| <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">functional</span></code> namespace and have the same |
| name as their corresponding free functions. For example, <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">functional</span><span class="special">::</span><span class="identifier">value</span></code> is a class that defines a function |
| object that does the same thing as the <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">value</span><span class="special">()</span></code> free function. |
| </p> |
| <a name="boost_proto.users_guide.getting_started.naming.primitive_transforms"></a><h6> |
| <a name="boost_proto.users_guide.getting_started.naming.primitive_transforms-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.naming.primitive_transforms">Primitive |
| Transforms</a> |
| </h6> |
| <p> |
| Proto also defines <span class="emphasis"><em>primitive transforms</em></span> -- class types |
| that can be used to compose larger transforms for manipulating expression |
| trees. Many of Proto's free functions have corresponding primitive transforms. |
| These live in the <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span></code> |
| namespace and their names have a leading underscore. For instance, the |
| transform corresponding to the <code class="computeroutput"><span class="identifier">value</span><span class="special">()</span></code> function is called <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span></code>. |
| </p> |
| <p> |
| The following table summarizes the discussion above: |
| </p> |
| <div class="table"> |
| <a name="id2286557"></a><p class="title"><b>Table 16.1. Proto Naming Conventions</b></p> |
| <div class="table-contents"><table class="table" summary="Proto Naming Conventions"> |
| <colgroup> |
| <col> |
| <col> |
| </colgroup> |
| <thead><tr> |
| <th> |
| <p> |
| Entity |
| </p> |
| </th> |
| <th> |
| <p> |
| Example |
| </p> |
| </th> |
| </tr></thead> |
| <tbody> |
| <tr> |
| <td> |
| <p> |
| Free Function |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">value</span><span class="special">()</span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| Metafunction |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">value</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| Function Object |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">functional</span><span class="special">::</span><span class="identifier">value</span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| Transform |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span></code> |
| </p> |
| </td> |
| </tr> |
| </tbody> |
| </table></div> |
| </div> |
| <br class="table-break"> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.getting_started.hello_world"></a><a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.hello_world" title="Hello World">Hello |
| World</a> |
| </h4></div></div></div> |
| <p> |
| Below is a very simple program that uses Proto to build an expression template |
| and then execute it. |
| </p> |
| <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">proto</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">typeof</span><span class="special">/</span><span class="identifier">std</span><span class="special">/</span><span class="identifier">ostream</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">;</span> |
| |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span> <span class="special">>::</span><span class="identifier">type</span> <span class="identifier">cout_</span> <span class="special">=</span> <span class="special">{</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Expr</span> <span class="special">></span> |
| <span class="keyword">void</span> <span class="identifier">evaluate</span><span class="special">(</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">expr</span> <span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">default_context</span> <span class="identifier">ctx</span><span class="special">;</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="identifier">evaluate</span><span class="special">(</span> <span class="identifier">cout_</span> <span class="special"><<</span> <span class="string">"hello"</span> <span class="special"><<</span> <span class="char">','</span> <span class="special"><<</span> <span class="string">" world"</span> <span class="special">);</span> |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| This program outputs the following: |
| </p> |
| <pre class="programlisting">hello, world |
| </pre> |
| <p> |
| This program builds an object representing the output operation and passes |
| it to an <code class="computeroutput"><span class="identifier">evaluate</span><span class="special">()</span></code> |
| function, which then executes it. |
| </p> |
| <p> |
| The basic idea of expression templates is to overload all the operators |
| so that, rather than evaluating the expression immediately, they build |
| a tree-like representation of the expression so that it can be evaluated |
| later. For each operator in an expression, at least one operand must be |
| Protofied in order for Proto's operator overloads to be found. In the expression |
| ... |
| </p> |
| <pre class="programlisting"><span class="identifier">cout_</span> <span class="special"><<</span> <span class="string">"hello"</span> <span class="special"><<</span> <span class="char">','</span> <span class="special"><<</span> <span class="string">" world"</span> |
| </pre> |
| <p> |
| ... the Protofied sub-expression is <code class="computeroutput"><span class="identifier">cout_</span></code>, |
| which is the Proto-ification of <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span></code>. |
| The presence of <code class="computeroutput"><span class="identifier">cout_</span></code> "infects" |
| the expression, and brings Proto's tree-building operator overloads into |
| consideration. Any literals in the expression are then Protofied by wrapping |
| them in a Proto terminal before they are combined into larger Proto expressions. |
| </p> |
| <p> |
| Once Proto's operator overloads have built the expression tree, the expression |
| can be lazily evaluated later by walking the tree. That is what <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">()</span></code> |
| does. It is a general tree-walking expression evaluator, whose behavior |
| is customizable via a <span class="emphasis"><em>context</em></span> parameter. The use of |
| <code class="computeroutput"><a class="link" href="../boost/proto/context/default_context.html" title="Struct default_context">proto::default_context</a></code> |
| assigns the standard meanings to the operators in the expression. (By using |
| a different context, you could give the operators in your expressions different |
| semantics. By default, Proto makes no assumptions about what operators |
| actually <span class="emphasis"><em>mean</em></span>.) |
| </p> |
| <a name="boost_proto.users_guide.getting_started.hello_world.proto_design_philosophy"></a><h6> |
| <a name="boost_proto.users_guide.getting_started.hello_world.proto_design_philosophy-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.hello_world.proto_design_philosophy">Proto |
| Design Philosophy</a> |
| </h6> |
| <p> |
| Before we continue, let's use the above example to illustrate an important |
| design principle of Proto's. The expression template created in the <span class="emphasis"><em>hello |
| world</em></span> example is totally general and abstract. It is not tied |
| in any way to any particular domain or application, nor does it have any |
| particular meaning or behavior on its own, until it is evaluated in a |
| <span class="emphasis"><em>context</em></span>. Expression templates are really just heterogeneous |
| trees, which might mean something in one domain, and something else entirely |
| in a different one. |
| </p> |
| <p> |
| As we'll see later, there is a way to create Proto expression trees that |
| are <span class="emphasis"><em>not</em></span> purely abstract, and that have meaning and |
| behaviors independent of any context. There is also a way to control which |
| operators are overloaded for your particular domain. But that is not the |
| default behavior. We'll see later why the default is often a good thing. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.getting_started.hello_calculator"></a><a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.hello_calculator" title="Hello Calculator">Hello |
| Calculator</a> |
| </h4></div></div></div> |
| <p> |
| "Hello, world" is nice, but it doesn't get you very far. Let's |
| use Proto to build a DSEL (domain-specific embedded language) for a lazily-evaluated |
| calculator. We'll see how to define the terminals in your mini-language, |
| how to compose them into larger expressions, and how to define an evaluation |
| context so that your expressions can do useful work. When we're done, we'll |
| have a mini-language that will allow us to declare a lazily-evaluated arithmetic |
| expression, such as <code class="computeroutput"><span class="special">(</span><span class="identifier">_2</span> |
| <span class="special">-</span> <span class="identifier">_1</span><span class="special">)</span> <span class="special">/</span> <span class="identifier">_2</span> |
| <span class="special">*</span> <span class="number">100</span></code>, |
| where <code class="computeroutput"><span class="identifier">_1</span></code> and <code class="computeroutput"><span class="identifier">_2</span></code> are placeholders for values to be |
| passed in when the expression is evaluated. |
| </p> |
| <a name="boost_proto.users_guide.getting_started.hello_calculator.defining_terminals"></a><h6> |
| <a name="boost_proto.users_guide.getting_started.hello_calculator.defining_terminals-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.hello_calculator.defining_terminals">Defining |
| Terminals</a> |
| </h6> |
| <p> |
| The first order of business is to define the placeholders <code class="computeroutput"><span class="identifier">_1</span></code> and <code class="computeroutput"><span class="identifier">_2</span></code>. |
| For that, we'll use the <code class="computeroutput"><a class="link" href="../boost/proto/terminal.html" title="Struct template terminal">proto::terminal<></a></code> |
| metafunction. |
| </p> |
| <pre class="programlisting"><span class="comment">// Define a placeholder type</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">I</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">placeholder</span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Define the Protofied placeholder terminals</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">placeholder</span><span class="special"><</span><span class="number">0</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">_1</span> <span class="special">=</span> <span class="special">{{}};</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">placeholder</span><span class="special"><</span><span class="number">1</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">_2</span> <span class="special">=</span> <span class="special">{{}};</span> |
| </pre> |
| <p> |
| The initialization may look a little odd at first, but there is a good |
| reason for doing things this way. The objects <code class="computeroutput"><span class="identifier">_1</span></code> |
| and <code class="computeroutput"><span class="identifier">_2</span></code> above do not require |
| run-time construction -- they are <span class="emphasis"><em>statically initialized</em></span>, |
| which means they are essentially initialized at compile time. See the |
| <a class="link" href="appendices.html#boost_proto.appendices.rationale.static_initialization" title="Static Initialization">Static |
| Initialization</a> section in the <a class="link" href="appendices.html#boost_proto.appendices.rationale" title="Appendix C: Rationale">Rationale</a> |
| appendix for more information. |
| </p> |
| <a name="boost_proto.users_guide.getting_started.hello_calculator.constructing_expression_trees"></a><h6> |
| <a name="boost_proto.users_guide.getting_started.hello_calculator.constructing_expression_trees-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.hello_calculator.constructing_expression_trees">Constructing |
| Expression Trees</a> |
| </h6> |
| <p> |
| Now that we have terminals, we can use Proto's operator overloads to combine |
| these terminals into larger expressions. So, for instance, we can immediately |
| say things like: |
| </p> |
| <pre class="programlisting"><span class="comment">// This builds an expression template</span> |
| <span class="special">(</span><span class="identifier">_2</span> <span class="special">-</span> <span class="identifier">_1</span><span class="special">)</span> <span class="special">/</span> <span class="identifier">_2</span> <span class="special">*</span> <span class="number">100</span><span class="special">;</span> |
| </pre> |
| <p> |
| This creates an expression tree with a node for each operator. The type |
| of the resulting object is large and complex, but we are not terribly interested |
| in it right now. |
| </p> |
| <p> |
| So far, the object is just a tree representing the expression. It has no |
| behavior. In particular, it is not yet a calculator. Below we'll see how |
| to make it a calculator by defining an evaluation context. |
| </p> |
| <a name="boost_proto.users_guide.getting_started.hello_calculator.evaluating_expression_trees"></a><h6> |
| <a name="boost_proto.users_guide.getting_started.hello_calculator.evaluating_expression_trees-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.hello_calculator.evaluating_expression_trees">Evaluating |
| Expression Trees</a> |
| </h6> |
| <p> |
| No doubt you want your expression templates to actually <span class="emphasis"><em>do</em></span> |
| something. One approach is to define an <span class="emphasis"><em>evaluation context</em></span>. |
| The context is like a function object that associates behaviors with the |
| node types in your expression tree. The following example should make it |
| clear. It is explained below. |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">calculator_context</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable_context</span><span class="special"><</span> <span class="identifier">calculator_context</span> <span class="keyword">const</span> <span class="special">></span> |
| <span class="special">{</span> |
| <span class="comment">// Values to replace the placeholders</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span> <span class="identifier">args</span><span class="special">;</span> |
| |
| <span class="comment">// Define the result type of the calculator.</span> |
| <span class="comment">// (This makes the calculator_context "callable".)</span> |
| <span class="keyword">typedef</span> <span class="keyword">double</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="comment">// Handle the placeholders:</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">I</span><span class="special">></span> |
| <span class="keyword">double</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">,</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="identifier">I</span><span class="special">>)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="keyword">this</span><span class="special">-></span><span class="identifier">args</span><span class="special">[</span><span class="identifier">I</span><span class="special">];</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| In <code class="computeroutput"><span class="identifier">calculator_context</span></code>, |
| we specify how Proto should evaluate the placeholder terminals by defining |
| the appropriate overloads of the function call operator. For any other |
| nodes in the expression tree (e.g., arithmetic operations or non-placeholder |
| terminals), Proto will evaluate the expression in the "default" |
| way. For example, a binary plus node is evaluated by first evaluating the |
| left and right operands and adding the results. Proto's default evaluator |
| uses the <a href="../../../libs/typeof/index.html" target="_top">Boost.Typeof</a> |
| library to compute return types. |
| </p> |
| <p> |
| Now that we have an evaluation context for our calculator, we can use it |
| to evaluate our arithmetic expressions, as below: |
| </p> |
| <pre class="programlisting"><span class="identifier">calculator_context</span> <span class="identifier">ctx</span><span class="special">;</span> |
| <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">args</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">45</span><span class="special">);</span> <span class="comment">// the value of _1 is 45</span> |
| <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">args</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">50</span><span class="special">);</span> <span class="comment">// the value of _2 is 50</span> |
| |
| <span class="comment">// Create an arithmetic expression and immediately evaluate it</span> |
| <span class="keyword">double</span> <span class="identifier">d</span> <span class="special">=</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span> <span class="special">(</span><span class="identifier">_2</span> <span class="special">-</span> <span class="identifier">_1</span><span class="special">)</span> <span class="special">/</span> <span class="identifier">_2</span> <span class="special">*</span> <span class="number">100</span><span class="special">,</span> <span class="identifier">ctx</span> <span class="special">);</span> |
| |
| <span class="comment">// This prints "10"</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">d</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| </pre> |
| <p> |
| Later, we'll see how to define more interesting evaluation contexts and |
| expression transforms that give you total control over how your expressions |
| are evaluated. |
| </p> |
| <a name="boost_proto.users_guide.getting_started.hello_calculator.customizing_expression_trees"></a><h6> |
| <a name="boost_proto.users_guide.getting_started.hello_calculator.customizing_expression_trees-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.hello_calculator.customizing_expression_trees">Customizing |
| Expression Trees</a> |
| </h6> |
| <p> |
| Our calculator DSEL is already pretty useful, and for many DSEL scenarios, |
| no more would be needed. But let's keep going. Imagine how much nicer it |
| would be if all calculator expressions overloaded <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code> so that they could be used as function |
| objects. We can do that by creating a calculator <span class="emphasis"><em>domain</em></span> |
| and telling Proto that all expressions in the calculator domain have extra |
| members. Here is how to define a calculator domain: |
| </p> |
| <pre class="programlisting"><span class="comment">// Forward-declare an expression wrapper</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">calculator</span><span class="special">;</span> |
| |
| <span class="comment">// Define a calculator domain. Expression within</span> |
| <span class="comment">// the calculator domain will be wrapped in the</span> |
| <span class="comment">// calculator<> expression wrapper.</span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_domain</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">generator</span><span class="special"><</span><span class="identifier">calculator</span><span class="special">></span> <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| The <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><></span></code> |
| type will be an expression wrapper. It will behave just like the expression |
| that it wraps, but it will have extra member functions that we will define. |
| The <code class="computeroutput"><span class="identifier">calculator_domain</span></code> is |
| what informs Proto about our wrapper. It is used below in the definition |
| of <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><></span></code>. |
| Read on for a description. |
| </p> |
| <pre class="programlisting"><span class="comment">// Define a calculator expression wrapper. It behaves just like</span> |
| <span class="comment">// the expression it wraps, but with an extra operator() member</span> |
| <span class="comment">// function that evaluates the expression. </span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">calculator</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">calculator</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>,</span> <span class="identifier">calculator_domain</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">calculator</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>,</span> <span class="identifier">calculator_domain</span><span class="special">></span> |
| <span class="identifier">base_type</span><span class="special">;</span> |
| |
| <span class="identifier">calculator</span><span class="special">(</span><span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span> <span class="special">=</span> <span class="identifier">Expr</span><span class="special">())</span> |
| <span class="special">:</span> <span class="identifier">base_type</span><span class="special">(</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="keyword">typedef</span> <span class="keyword">double</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="comment">// Overload operator() to invoke proto::eval() with</span> |
| <span class="comment">// our calculator_context.</span> |
| <span class="keyword">double</span> <span class="keyword">operator</span><span class="special">()(</span><span class="keyword">double</span> <span class="identifier">a1</span> <span class="special">=</span> <span class="number">0</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">a2</span> <span class="special">=</span> <span class="number">0</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">calculator_context</span> <span class="identifier">ctx</span><span class="special">;</span> |
| <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">args</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">a1</span><span class="special">);</span> |
| <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">args</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">a2</span><span class="special">);</span> |
| |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| The <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><></span></code> |
| struct is an expression <span class="emphasis"><em>extension</em></span>. It uses <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><></span></code> |
| to effectively add additional members to an expression type. When composing |
| larger expressions from smaller ones, Proto notes what domain the smaller |
| expressions are in. The larger expression is in the same domain and is |
| automatically wrapped in the domain's extension wrapper. |
| </p> |
| <p> |
| All that remains to be done is to put our placeholders in the calculator |
| domain. We do that by wrapping them in our <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><></span></code> wrapper, as below: |
| </p> |
| <pre class="programlisting"><span class="comment">// Define the Protofied placeholder terminals, in the</span> |
| <span class="comment">// calculator domain.</span> |
| <span class="identifier">calculator</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">placeholder</span><span class="special"><</span><span class="number">0</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span><span class="special">></span> <span class="keyword">const</span> <span class="identifier">_1</span><span class="special">;</span> |
| <span class="identifier">calculator</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">placeholder</span><span class="special"><</span><span class="number">1</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span><span class="special">></span> <span class="keyword">const</span> <span class="identifier">_2</span><span class="special">;</span> |
| </pre> |
| <p> |
| Any larger expression that contain these placeholders will automatically |
| be wrapped in the <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><></span></code> wrapper and have our <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code> |
| overload. That means we can use them as function objects as follows. |
| </p> |
| <pre class="programlisting"><span class="keyword">double</span> <span class="identifier">result</span> <span class="special">=</span> <span class="special">((</span><span class="identifier">_2</span> <span class="special">-</span> <span class="identifier">_1</span><span class="special">)</span> <span class="special">/</span> <span class="identifier">_2</span> <span class="special">*</span> <span class="number">100</span><span class="special">)(</span><span class="number">45.0</span><span class="special">,</span> <span class="number">50.0</span><span class="special">);</span> |
| <span class="identifier">assert</span><span class="special">(</span><span class="identifier">result</span> <span class="special">==</span> <span class="special">(</span><span class="number">50.0</span> <span class="special">-</span> <span class="number">45.0</span><span class="special">)</span> <span class="special">/</span> <span class="number">50.0</span> <span class="special">*</span> <span class="number">100</span><span class="special">));</span> |
| </pre> |
| <p> |
| Since calculator expressions are now valid function objects, we can use |
| them with standard algorithms, as shown below: |
| </p> |
| <pre class="programlisting"><span class="keyword">double</span> <span class="identifier">a1</span><span class="special">[</span><span class="number">4</span><span class="special">]</span> <span class="special">=</span> <span class="special">{</span> <span class="number">56</span><span class="special">,</span> <span class="number">84</span><span class="special">,</span> <span class="number">37</span><span class="special">,</span> <span class="number">69</span> <span class="special">};</span> |
| <span class="keyword">double</span> <span class="identifier">a2</span><span class="special">[</span><span class="number">4</span><span class="special">]</span> <span class="special">=</span> <span class="special">{</span> <span class="number">65</span><span class="special">,</span> <span class="number">120</span><span class="special">,</span> <span class="number">60</span><span class="special">,</span> <span class="number">70</span> <span class="special">};</span> |
| <span class="keyword">double</span> <span class="identifier">a3</span><span class="special">[</span><span class="number">4</span><span class="special">]</span> <span class="special">=</span> <span class="special">{</span> <span class="number">0</span> <span class="special">};</span> |
| |
| <span class="comment">// Use std::transform() and a calculator expression</span> |
| <span class="comment">// to calculate percentages given two input sequences:</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">transform</span><span class="special">(</span><span class="identifier">a1</span><span class="special">,</span> <span class="identifier">a1</span><span class="special">+</span><span class="number">4</span><span class="special">,</span> <span class="identifier">a2</span><span class="special">,</span> <span class="identifier">a3</span><span class="special">,</span> <span class="special">(</span><span class="identifier">_2</span> <span class="special">-</span> <span class="identifier">_1</span><span class="special">)</span> <span class="special">/</span> <span class="identifier">_2</span> <span class="special">*</span> <span class="number">100</span><span class="special">);</span> |
| </pre> |
| <p> |
| Now, let's use the calculator example to explore some other useful features |
| of Proto. |
| </p> |
| <a name="boost_proto.users_guide.getting_started.hello_calculator.detecting_invalid_expressions"></a><h6> |
| <a name="boost_proto.users_guide.getting_started.hello_calculator.detecting_invalid_expressions-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.hello_calculator.detecting_invalid_expressions">Detecting |
| Invalid Expressions</a> |
| </h6> |
| <p> |
| You may have noticed that you didn't have to define an overloaded <code class="computeroutput"><span class="keyword">operator</span><span class="special">-()</span></code> |
| or <code class="computeroutput"><span class="keyword">operator</span><span class="special">/()</span></code> |
| -- Proto defined them for you. In fact, Proto overloads <span class="emphasis"><em>all</em></span> |
| the operators for you, even though they may not mean anything in your domain-specific |
| language. That means it may be possible to create expressions that are |
| invalid in your domain. You can detect invalid expressions with Proto by |
| defining the <span class="emphasis"><em>grammar</em></span> of your domain-specific language. |
| </p> |
| <p> |
| For simplicity, assume that our calculator DSEL should only allow addition, |
| subtraction, multiplication and division. Any expression involving any |
| other operator is invalid. Using Proto, we can state this requirement by |
| defining the grammar of the calculator DSEL. It looks as follows: |
| </p> |
| <pre class="programlisting"><span class="comment">// Define the grammar of calculator expressions</span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_grammar</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span> <span class="identifier">calculator_grammar</span><span class="special">,</span> <span class="identifier">calculator_grammar</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">minus</span><span class="special"><</span> <span class="identifier">calculator_grammar</span><span class="special">,</span> <span class="identifier">calculator_grammar</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">multiplies</span><span class="special"><</span> <span class="identifier">calculator_grammar</span><span class="special">,</span> <span class="identifier">calculator_grammar</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">divides</span><span class="special"><</span> <span class="identifier">calculator_grammar</span><span class="special">,</span> <span class="identifier">calculator_grammar</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span> <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| You can read the above grammar as follows: an expression tree conforms |
| to the calculator grammar if it is a binary plus, minus, multiplies or |
| divides node, where both child nodes also conform to the calculator grammar; |
| or if it is a terminal. In a Proto grammar, <code class="computeroutput"><a class="link" href="../boost/proto/_.html" title="Struct _">proto::_</a></code> is a wildcard that matches |
| any type, so <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span> <span class="special">></span></code> |
| matches any terminal, whether it is a placeholder or a literal. |
| </p> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| This grammar is actually a little looser than we would like. Only placeholders |
| and literals that are convertible to doubles are valid terminals. Later |
| on we'll see how to express things like that in Proto grammars. |
| </p></td></tr> |
| </table></div> |
| <p> |
| Once you have defined the grammar of your DSEL, you can use the <code class="computeroutput"><a class="link" href="../boost/proto/matches.html" title="Struct template matches">proto::matches<></a></code> metafunction to check |
| whether a given expression type conforms to the grammar. For instance, |
| we might add the following to our <code class="computeroutput"><span class="identifier">calculator</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code> overload: |
| </p> |
| <pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">calculator</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span> <span class="comment">/* ... as before ... */</span> <span class="special">></span> |
| <span class="special">{</span> |
| <span class="comment">/* ... */</span> |
| <span class="keyword">double</span> <span class="keyword">operator</span><span class="special">()(</span><span class="keyword">double</span> <span class="identifier">a1</span> <span class="special">=</span> <span class="number">0</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">a2</span> <span class="special">=</span> <span class="number">0</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="comment">// Check here that the expression we are about to</span> |
| <span class="comment">// evaluate actually conforms to the calculator grammar.</span> |
| <span class="identifier">BOOST_MPL_ASSERT</span><span class="special">((</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">calculator_grammar</span><span class="special">>));</span> |
| <span class="comment">/* ... */</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| The addition of the <code class="computeroutput"><span class="identifier">BOOST_MPL_ASSERT</span><span class="special">()</span></code> line enforces at compile time that we |
| only evaluate expressions that conform to the calculator DSEL's grammar. |
| With Proto grammars, <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><></span></code> and <code class="computeroutput"><span class="identifier">BOOST_MPL_ASSERT</span><span class="special">()</span></code> it is very easy to give the users of |
| your DSEL short and readable compile-time errors when they accidentally |
| misuse your DSEL. |
| </p> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| <code class="computeroutput"><span class="identifier">BOOST_MPL_ASSERT</span><span class="special">()</span></code> |
| is part of the Boost Metaprogramming Library. To use it, just <code class="computeroutput"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mpl</span><span class="special">/</span><span class="identifier">assert</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span></code>. |
| </p></td></tr> |
| </table></div> |
| <a name="boost_proto.users_guide.getting_started.hello_calculator.controlling_operator_overloads"></a><h6> |
| <a name="boost_proto.users_guide.getting_started.hello_calculator.controlling_operator_overloads-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.hello_calculator.controlling_operator_overloads">Controlling |
| Operator Overloads</a> |
| </h6> |
| <p> |
| Grammars and <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><></span></code> |
| make it possible to detect when a user has created an invalid expression |
| and issue a compile-time error. But what if you want to prevent users from |
| creating invalid expressions in the first place? By using grammars and |
| domains together, you can disable any of Proto's operator overloads that |
| would create an invalid expression. It is as simple as specifying the DSEL's |
| grammar when you define the domain, as shown below: |
| </p> |
| <pre class="programlisting"><span class="comment">// Define a calculator domain. Expression within</span> |
| <span class="comment">// the calculator domain will be wrapped in the</span> |
| <span class="comment">// calculator<> expression wrapper.</span> |
| <span class="comment">// NEW: Any operator overloads that would create an</span> |
| <span class="comment">// expression that does not conform to the</span> |
| <span class="comment">// calculator grammar is automatically disabled.</span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_domain</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">generator</span><span class="special"><</span><span class="identifier">calculator</span><span class="special">>,</span> <span class="identifier">calculator_grammar</span> <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| The only thing we changed is we added <code class="computeroutput"><span class="identifier">calculator_grammar</span></code> |
| as the second template parameter to the <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><></span></code> template when defining <code class="computeroutput"><span class="identifier">calculator_domain</span></code>. With this simple addition, |
| we disable any of Proto's operator overloads that would create an invalid |
| calculator expression. |
| </p> |
| <a name="boost_proto.users_guide.getting_started.hello_calculator.____and_much_more"></a><h6> |
| <a name="boost_proto.users_guide.getting_started.hello_calculator.____and_much_more-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.hello_calculator.____and_much_more">... |
| And Much More</a> |
| </h6> |
| <p> |
| Hopefully, this gives you an idea of what sorts of things Proto can do |
| for you. But this only scratches the surface. The rest of this users' guide |
| will describe all these features and others in more detail. |
| </p> |
| <p> |
| Happy metaprogramming! |
| </p> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="boost_proto.users_guide.front_end"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end" title="Fronts Ends: Defining Terminals and Non-Terminals of Your DSEL">Fronts Ends: Defining |
| Terminals and Non-Terminals of Your DSEL</a> |
| </h3></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.front_end.making_terminals">Making |
| Terminals</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.front_end.proto_s_operator_overloads">Proto's |
| Operator Overloads</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.front_end.making_lazy_functions">Making |
| Lazy Functions</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.front_end.adding_members_by_extending_expressions">Adding |
| Members by Extending Expressions</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.front_end.define_operators">Adapting |
| Existing Types to Proto</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.front_end.code_repetition">Generating |
| Repetitive Code with the Preprocessor</a></span></dt> |
| </dl></div> |
| <p> |
| Here is the fun part: designing your own mini-programming language. In this |
| section we'll talk about the nuts and bolts of designing a DSEL interface |
| using Proto. We'll cover the definition of terminals and lazy functions that |
| the users of your DSEL will get to program with. We'll also talk about Proto's |
| expression template-building operator overloads, and about ways to add additional |
| members to expressions within your domain. |
| </p> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.front_end.making_terminals"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.making_terminals" title="Making Terminals">Making |
| Terminals</a> |
| </h4></div></div></div> |
| <p> |
| As we saw with the Calculator example from the Introduction, the simplest |
| way to get a DSEL up and running is simply to define some terminals, as |
| follows. |
| </p> |
| <pre class="programlisting"><span class="comment">// Define a literal integer Proto expression.</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">>::</span><span class="identifier">type</span> <span class="identifier">i</span> <span class="special">=</span> <span class="special">{</span><span class="number">0</span><span class="special">};</span> |
| |
| <span class="comment">// This creates an expression template.</span> |
| <span class="identifier">i</span> <span class="special">+</span> <span class="number">1</span><span class="special">;</span> |
| </pre> |
| <p> |
| With some terminals and Proto's operator overloads, you can immediately |
| start creating expression templates. |
| </p> |
| <p> |
| Defining terminals -- with aggregate initialization -- can be a little |
| awkward at times. Proto provides an easier-to-use wrapper for literals |
| that can be used to construct Protofied terminal expressions. It's called |
| <code class="computeroutput"><a class="link" href="../boost/proto/literal.html" title="Struct template literal">proto::literal<></a></code>. |
| </p> |
| <pre class="programlisting"><span class="comment">// Define a literal integer Proto expression.</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">literal</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> |
| |
| <span class="comment">// Proto literals are really just Proto terminal expressions.</span> |
| <span class="comment">// For example, this builds a Proto expression template:</span> |
| <span class="identifier">i</span> <span class="special">+</span> <span class="number">1</span><span class="special">;</span> |
| </pre> |
| <p> |
| There is also a <code class="computeroutput"><a class="link" href="../boost/proto/lit.html" title="Function lit">proto::lit()</a></code> function for constructing |
| a <code class="computeroutput"><a class="link" href="../boost/proto/literal.html" title="Struct template literal">proto::literal<></a></code> in-place. The above |
| expression can simply be written as: |
| </p> |
| <pre class="programlisting"><span class="comment">// proto::lit(0) creates an integer terminal expression</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">lit</span><span class="special">(</span><span class="number">0</span><span class="special">)</span> <span class="special">+</span> <span class="number">1</span><span class="special">;</span> |
| </pre> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.front_end.proto_s_operator_overloads"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.proto_s_operator_overloads" title="Proto's Operator Overloads">Proto's |
| Operator Overloads</a> |
| </h4></div></div></div> |
| <p> |
| Once we have some Proto terminals, expressions involving those terminals |
| build expression trees for us. Proto defines overloads for each of C++'s |
| overloadable operators in the <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span></code> |
| namespace. As long as one operand is a Proto expression, the result of |
| the operation is a tree node representing that operation. |
| </p> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| Proto's operator overloads live in the <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span></code> |
| namespace and are found via ADL (argument-dependent lookup). That is |
| why expressions must be "tainted" with Proto-ness for Proto |
| to be able to build trees out of expressions. |
| </p></td></tr> |
| </table></div> |
| <p> |
| As a result of Proto's operator overloads, we can say: |
| </p> |
| <pre class="programlisting"><span class="special">-</span><span class="identifier">_1</span><span class="special">;</span> <span class="comment">// OK, build a unary-negate tree node</span> |
| <span class="identifier">_1</span> <span class="special">+</span> <span class="number">42</span><span class="special">;</span> <span class="comment">// OK, build a binary-plus tree node</span> |
| </pre> |
| <p> |
| For the most part, this Just Works and you don't need to think about it, |
| but a few operators are special and it can be helpful to know how Proto |
| handles them. |
| </p> |
| <a name="boost_proto.users_guide.front_end.proto_s_operator_overloads.assignment__subscript__and_function_call_operators"></a><h6> |
| <a name="boost_proto.users_guide.front_end.proto_s_operator_overloads.assignment__subscript__and_function_call_operators-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.front_end.proto_s_operator_overloads.assignment__subscript__and_function_call_operators">Assignment, |
| Subscript, and Function Call Operators</a> |
| </h6> |
| <p> |
| Proto also overloads <code class="computeroutput"><span class="keyword">operator</span><span class="special">=</span></code>, <code class="computeroutput"><span class="keyword">operator</span><span class="special">[]</span></code>, and <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code>, but these operators are member functions |
| of the expression template rather than free functions in Proto's namespace. |
| The following are valid Proto expressions: |
| </p> |
| <pre class="programlisting"><span class="identifier">_1</span> <span class="special">=</span> <span class="number">5</span><span class="special">;</span> <span class="comment">// OK, builds a binary assign tree node</span> |
| <span class="identifier">_1</span><span class="special">[</span><span class="number">6</span><span class="special">];</span> <span class="comment">// OK, builds a binary subscript tree node</span> |
| <span class="identifier">_1</span><span class="special">();</span> <span class="comment">// OK, builds a unary function tree node</span> |
| <span class="identifier">_1</span><span class="special">(</span><span class="number">7</span><span class="special">);</span> <span class="comment">// OK, builds a binary function tree node</span> |
| <span class="identifier">_1</span><span class="special">(</span><span class="number">8</span><span class="special">,</span><span class="number">9</span><span class="special">);</span> <span class="comment">// OK, builds a ternary function tree node</span> |
| <span class="comment">// ... etc.</span> |
| </pre> |
| <p> |
| For the first two lines, assignment and subscript, it should be fairly |
| unsurprising that the resulting expression node should be binary. After |
| all, there are two operands in each expression. It may be surprising at |
| first that what appears to be a function call with no arguments, <code class="computeroutput"><span class="identifier">_1</span><span class="special">()</span></code>, |
| actually creates an expression node with one child. The child is <code class="computeroutput"><span class="identifier">_1</span></code> itself. Likewise, the expression |
| <code class="computeroutput"><span class="identifier">_1</span><span class="special">(</span><span class="number">7</span><span class="special">)</span></code> has two |
| children: <code class="computeroutput"><span class="identifier">_1</span></code> and <code class="computeroutput"><span class="number">7</span></code>. |
| </p> |
| <p> |
| Because these operators can only be defined as member functions, the following |
| expressions are invalid: |
| </p> |
| <pre class="programlisting"><span class="keyword">int</span> <span class="identifier">i</span><span class="special">;</span> |
| <span class="identifier">i</span> <span class="special">=</span> <span class="identifier">_1</span><span class="special">;</span> <span class="comment">// ERROR: cannot assign _1 to an int</span> |
| |
| <span class="keyword">int</span> <span class="special">*</span><span class="identifier">p</span><span class="special">;</span> |
| <span class="identifier">p</span><span class="special">[</span><span class="identifier">_1</span><span class="special">];</span> <span class="comment">// ERROR: cannot use _1 as an index</span> |
| |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">sin</span><span class="special">(</span><span class="identifier">_1</span><span class="special">);</span> <span class="comment">// ERROR: cannot call std::sin() with _1</span> |
| </pre> |
| <p> |
| Also, C++ has special rules for overloads of <code class="computeroutput"><span class="keyword">operator</span><span class="special">-></span></code> that make it useless for building |
| expression templates, so Proto does not overload it. |
| </p> |
| <a name="boost_proto.users_guide.front_end.proto_s_operator_overloads.the_address_of_operator"></a><h6> |
| <a name="boost_proto.users_guide.front_end.proto_s_operator_overloads.the_address_of_operator-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.front_end.proto_s_operator_overloads.the_address_of_operator">The |
| Address-Of Operator</a> |
| </h6> |
| <p> |
| Proto overloads the address-of operator for expression types, so that the |
| following code creates a new unary address-of tree node: |
| </p> |
| <pre class="programlisting"><span class="special">&</span><span class="identifier">_1</span><span class="special">;</span> <span class="comment">// OK, creates a unary address-of tree node</span> |
| </pre> |
| <p> |
| It does <span class="emphasis"><em>not</em></span> return the address of the <code class="computeroutput"><span class="identifier">_1</span></code> object. However, there is special |
| code in Proto such that a unary address-of node is implicitly convertible |
| to a pointer to its child. In other words, the following code works and |
| does what you might expect, but not in the obvious way: |
| </p> |
| <pre class="programlisting"><span class="keyword">typedef</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="number">0</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> |
| <span class="identifier">_1_type</span><span class="special">;</span> |
| |
| <span class="identifier">_1_type</span> <span class="keyword">const</span> <span class="identifier">_1</span> <span class="special">=</span> <span class="special">{{}};</span> |
| <span class="identifier">_1_type</span> <span class="keyword">const</span> <span class="special">*</span> <span class="identifier">p</span> <span class="special">=</span> <span class="special">&</span><span class="identifier">_1</span><span class="special">;</span> <span class="comment">// OK, &_1 implicitly converted</span> |
| </pre> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.front_end.making_lazy_functions"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.making_lazy_functions" title="Making Lazy Functions">Making |
| Lazy Functions</a> |
| </h4></div></div></div> |
| <p> |
| If we limited ourselves to nothing but terminals and operator overloads, |
| our domain-specific embedded languages wouldn't be very expressive. Imagine |
| that we wanted to extend our calculator DSEL with a full suite of math |
| functions like <code class="computeroutput"><span class="identifier">sin</span><span class="special">()</span></code> |
| and <code class="computeroutput"><span class="identifier">pow</span><span class="special">()</span></code> |
| that we could invoke lazily as follows. |
| </p> |
| <pre class="programlisting"><span class="comment">// A calculator expression that takes one argument</span> |
| <span class="comment">// and takes the sine of it.</span> |
| <span class="identifier">sin</span><span class="special">(</span><span class="identifier">_1</span><span class="special">);</span> |
| </pre> |
| <p> |
| We would like the above to create an expression template representing a |
| function invocation. When that expression is evaluated, it should cause |
| the function to be invoked. (At least, that's the meaning of function invocation |
| we'd like the calculator DSEL to have.) You can define <code class="computeroutput"><span class="identifier">sin</span></code> |
| quite simply as follows. |
| </p> |
| <pre class="programlisting"><span class="comment">// "sin" is a Proto terminal containing a function pointer</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="keyword">double</span><span class="special">(*)(</span><span class="keyword">double</span><span class="special">)</span> <span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">sin</span> <span class="special">=</span> <span class="special">{&</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">sin</span><span class="special">};</span> |
| </pre> |
| <p> |
| In the above, we define <code class="computeroutput"><span class="identifier">sin</span></code> |
| as a Proto terminal containing a pointer to the <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">sin</span><span class="special">()</span></code> function. Now we can use <code class="computeroutput"><span class="identifier">sin</span></code> as a lazy function. The <code class="computeroutput"><span class="identifier">default_context</span></code> that we saw in the Introduction |
| knows how to evaluate lazy functions. Consider the following: |
| </p> |
| <pre class="programlisting"><span class="keyword">double</span> <span class="identifier">pi</span> <span class="special">=</span> <span class="number">3.1415926535</span><span class="special">;</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">default_context</span> <span class="identifier">ctx</span><span class="special">;</span> |
| <span class="comment">// Create a lazy "sin" invocation and immediately evaluate it</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span> <span class="identifier">sin</span><span class="special">(</span><span class="identifier">pi</span><span class="special">/</span><span class="number">2</span><span class="special">),</span> <span class="identifier">ctx</span> <span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| </pre> |
| <p> |
| The above code prints out: |
| </p> |
| <pre class="programlisting">1</pre> |
| <p> |
| It is important to note that there is nothing special about terminals that |
| contain function pointers. <span class="emphasis"><em>Any</em></span> Proto expression has |
| an overloaded function call operator. Consider: |
| </p> |
| <pre class="programlisting"><span class="comment">// This compiles!</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">lit</span><span class="special">(</span><span class="number">1</span><span class="special">)(</span><span class="number">2</span><span class="special">)(</span><span class="number">3</span><span class="special">,</span><span class="number">4</span><span class="special">)(</span><span class="number">5</span><span class="special">,</span><span class="number">6</span><span class="special">,</span><span class="number">7</span><span class="special">,</span><span class="number">8</span><span class="special">);</span> |
| </pre> |
| <p> |
| That may look strange at first. It creates an integer terminal with <code class="computeroutput"><a class="link" href="../boost/proto/lit.html" title="Function lit">proto::lit()</a></code>, and then invokes it like |
| a function again and again. What does it mean? To be sure, the <code class="computeroutput"><span class="identifier">default_context</span></code> wouldn't know what to |
| do with it. The <code class="computeroutput"><span class="identifier">default_context</span></code> |
| only knows how to evaluate expressions that are sufficiently C++-like. |
| In the case of function call expressions, the left hand side must evaluate |
| to something that can be invoked: a pointer to a function, a reference |
| to a function, or a TR1-style function object. That doesn't stop you from |
| defining your own evaluation context that gives that expression a meaning. |
| But more on that later. |
| </p> |
| <a name="boost_proto.users_guide.front_end.making_lazy_functions.making_lazy_functions__continued"></a><h6> |
| <a name="boost_proto.users_guide.front_end.making_lazy_functions.making_lazy_functions__continued-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.front_end.making_lazy_functions.making_lazy_functions__continued">Making |
| Lazy Functions, Continued</a> |
| </h6> |
| <p> |
| Now, what if we wanted to add a <code class="computeroutput"><span class="identifier">pow</span><span class="special">()</span></code> function to our calculator DSEL that |
| users could invoke as follows? |
| </p> |
| <pre class="programlisting"><span class="comment">// A calculator expression that takes one argument</span> |
| <span class="comment">// and raises it to the 2nd power</span> |
| <span class="identifier">pow</span><span class="special"><</span> <span class="number">2</span> <span class="special">>(</span><span class="identifier">_1</span><span class="special">);</span> |
| </pre> |
| <p> |
| The simple technique described above of making <code class="computeroutput"><span class="identifier">pow</span></code> |
| a terminal containing a function pointer doesn't work here. If <code class="computeroutput"><span class="identifier">pow</span></code> is an object, then the expression |
| <code class="computeroutput"><span class="identifier">pow</span><span class="special"><</span> |
| <span class="number">2</span> <span class="special">>(</span><span class="identifier">_1</span><span class="special">)</span></code> is |
| not valid C++. <code class="computeroutput"><span class="identifier">pow</span></code> needs |
| to be a real function template. But it must be an unusual function; it |
| must return an expression template. |
| </p> |
| <p> |
| Before we can write the <code class="computeroutput"><span class="identifier">pow</span><span class="special">()</span></code> function, we need a function object that |
| wraps an invocation of <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pow</span><span class="special">()</span></code>. |
| </p> |
| <pre class="programlisting"><span class="comment">// Define a pow_fun function object</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">Exp</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">pow_fun</span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">double</span> <span class="identifier">result_type</span><span class="special">;</span> |
| <span class="keyword">double</span> <span class="keyword">operator</span><span class="special">()(</span><span class="keyword">double</span> <span class="identifier">d</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">pow</span><span class="special">(</span><span class="identifier">d</span><span class="special">,</span> <span class="identifier">Exp</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| Now, let's try to define a function template that returns an expression |
| template. We'll use the <code class="computeroutput"><a class="link" href="../boost/proto/function.html" title="Struct template function">proto::function<></a></code> |
| metafunction to calculate the type of a Proto expression that represents |
| a function call. It is analogous to <code class="computeroutput"><a class="link" href="../boost/proto/terminal.html" title="Struct template terminal">proto::terminal<></a></code>. |
| (We'll see a couple of different ways to solve this problem, and each will |
| demonstrate another utility for defining Proto front-ends.) |
| </p> |
| <pre class="programlisting"><span class="comment">// Define a lazy pow() function for the calculator DSEL.</span> |
| <span class="comment">// Can be used as: pow< 2 >(_1)</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">Exp</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Arg</span><span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">function</span><span class="special"><</span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">pow_fun</span><span class="special"><</span><span class="identifier">Exp</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">,</span> <span class="identifier">Arg</span> <span class="keyword">const</span> <span class="special">&</span> |
| <span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> |
| <span class="identifier">pow</span><span class="special">(</span><span class="identifier">Arg</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">arg</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">function</span><span class="special"><</span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">pow_fun</span><span class="special"><</span><span class="identifier">Exp</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">,</span> <span class="identifier">Arg</span> <span class="keyword">const</span> <span class="special">&</span> |
| <span class="special">>::</span><span class="identifier">type</span> |
| <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">result_type</span> <span class="identifier">result</span> <span class="special">=</span> <span class="special">{{{}},</span> <span class="identifier">arg</span><span class="special">};</span> |
| <span class="keyword">return</span> <span class="identifier">result</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| In the code above, notice how the <code class="computeroutput"><a class="link" href="../boost/proto/function.html" title="Struct template function">proto::function<></a></code> |
| and <code class="computeroutput"><a class="link" href="../boost/proto/terminal.html" title="Struct template terminal">proto::terminal<></a></code> metafunctions are used |
| to calculate the return type: <code class="computeroutput"><span class="identifier">pow</span><span class="special">()</span></code> returns an expression template representing |
| a function call where the first child is the function to call and the second |
| is the argument to the function. (Unfortunately, the same type calculation |
| is repeated in the body of the function so that we can initialize a local |
| variable of the correct type. We'll see in a moment how to avoid that.) |
| </p> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| As with <code class="computeroutput"><a class="link" href="../boost/proto/function.html" title="Struct template function">proto::function<></a></code>, there are metafunctions |
| corresponding to all of the overloadable C++ operators for calculating |
| expression types. |
| </p></td></tr> |
| </table></div> |
| <p> |
| With the above definition of the <code class="computeroutput"><span class="identifier">pow</span><span class="special">()</span></code> function, we can create calculator expressions |
| like the one below and evaluate them using the <code class="computeroutput"><span class="identifier">calculator_context</span></code> |
| we implemented in the Introduction. |
| </p> |
| <pre class="programlisting"><span class="comment">// Initialize a calculator context</span> |
| <span class="identifier">calculator_context</span> <span class="identifier">ctx</span><span class="special">;</span> |
| <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">args</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">3</span><span class="special">);</span> <span class="comment">// let _1 be 3</span> |
| |
| <span class="comment">// Create a calculator expression that takes one argument,</span> |
| <span class="comment">// adds one to it, and raises it to the 2nd power; and then</span> |
| <span class="comment">// immediately evaluate it using the calculator_context.</span> |
| <span class="identifier">assert</span><span class="special">(</span> <span class="number">16</span> <span class="special">==</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span> <span class="identifier">pow</span><span class="special"><</span><span class="number">2</span><span class="special">>(</span> <span class="identifier">_1</span> <span class="special">+</span> <span class="number">1</span> <span class="special">),</span> <span class="identifier">ctx</span> <span class="special">)</span> <span class="special">);</span> |
| </pre> |
| <a name="boost_proto.users_guide.front_end.making_lazy_functions.protofying_lazy_function_arguments"></a><h6> |
| <a name="boost_proto.users_guide.front_end.making_lazy_functions.protofying_lazy_function_arguments-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.front_end.making_lazy_functions.protofying_lazy_function_arguments">Protofying |
| Lazy Function Arguments</a> |
| </h6> |
| <p> |
| Above, we defined a <code class="computeroutput"><span class="identifier">pow</span><span class="special">()</span></code> function template that returns an expression |
| template representing a lazy function invocation. But if we tried to call |
| it as below, we'll run into a problem. |
| </p> |
| <pre class="programlisting"><span class="comment">// ERROR: pow() as defined above doesn't work when</span> |
| <span class="comment">// called with a non-Proto argument.</span> |
| <span class="identifier">pow</span><span class="special"><</span> <span class="number">2</span> <span class="special">>(</span> <span class="number">4</span> <span class="special">);</span> |
| </pre> |
| <p> |
| Proto expressions can only have other Proto expressions as children. But |
| if we look at <code class="computeroutput"><span class="identifier">pow</span><span class="special">()</span></code>'s |
| function signature, we can see that if we pass it a non-Proto object, it |
| will try to make it a child. |
| </p> |
| <pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">Exp</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Arg</span><span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">function</span><span class="special"><</span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">pow_fun</span><span class="special"><</span><span class="identifier">Exp</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">,</span> <span class="identifier">Arg</span> <span class="keyword">const</span> <span class="special">&</span> <span class="comment">// <=== ERROR! This may not be a Proto type!</span> |
| <span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> |
| <span class="identifier">pow</span><span class="special">(</span><span class="identifier">Arg</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">arg</span><span class="special">)</span> |
| </pre> |
| <p> |
| What we want is a way to make <code class="computeroutput"><span class="identifier">Arg</span></code> |
| into a Proto terminal if it is not a Proto expression already, and leave |
| it alone if it is. For that, we can use <code class="computeroutput"><a class="link" href="../boost/proto/as_child_id1386369.html" title="Function as_child">proto::as_child()</a></code>. |
| The following implementation of the <code class="computeroutput"><span class="identifier">pow</span><span class="special">()</span></code> function handles all argument types, |
| expression templates or otherwise. |
| </p> |
| <pre class="programlisting"><span class="comment">// Define a lazy pow() function for the calculator DSEL. Use</span> |
| <span class="comment">// proto::as_child() to Protofy the argument, but only if it</span> |
| <span class="comment">// is not a Proto expression type to begin with!</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">Exp</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Arg</span><span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">function</span><span class="special"><</span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">pow_fun</span><span class="special"><</span><span class="identifier">Exp</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">as_child</span><span class="special"><</span><span class="identifier">Arg</span> <span class="keyword">const</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> |
| <span class="identifier">pow</span><span class="special">(</span><span class="identifier">Arg</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">arg</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">function</span><span class="special"><</span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">pow_fun</span><span class="special"><</span><span class="identifier">Exp</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">as_child</span><span class="special"><</span><span class="identifier">Arg</span> <span class="keyword">const</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">>::</span><span class="identifier">type</span> |
| <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">result_type</span> <span class="identifier">result</span> <span class="special">=</span> <span class="special">{{{}},</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_child</span><span class="special">(</span><span class="identifier">arg</span><span class="special">)};</span> |
| <span class="keyword">return</span> <span class="identifier">result</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| Notice how we use the <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">as_child</span><span class="special"><></span></code> metafunction to calculate the return |
| type, and the <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_child</span><span class="special">()</span></code> |
| function to actually normalize the argument. |
| </p> |
| <a name="boost_proto.users_guide.front_end.making_lazy_functions.lazy_functions_made_simple_with__literal_make_expr____literal_"></a><h6> |
| <a name="boost_proto.users_guide.front_end.making_lazy_functions.lazy_functions_made_simple_with__literal_make_expr____literal_-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.front_end.making_lazy_functions.lazy_functions_made_simple_with__literal_make_expr____literal_">Lazy |
| Functions Made Simple With <code class="literal">make_expr()</code></a> |
| </h6> |
| <p> |
| The versions of the <code class="computeroutput"><span class="identifier">pow</span><span class="special">()</span></code> function we've seen above are rather |
| verbose. In the return type calculation, you have to be very explicit about |
| wrapping non-Proto types. Worse, you have to restate the return type calculation |
| in the body of <code class="computeroutput"><span class="identifier">pow</span><span class="special">()</span></code> |
| itself. Proto provides a helper for building expression templates directly |
| that handles these mundane details for you. It's called <code class="computeroutput"><a class="link" href="../boost/proto/make_expr_id1362445.html" title="Function make_expr">proto::make_expr()</a></code>. |
| We can redefine <code class="computeroutput"><span class="identifier">pow</span><span class="special">()</span></code> |
| with it as below. |
| </p> |
| <pre class="programlisting"><span class="comment">// Define a lazy pow() function for the calculator DSEL.</span> |
| <span class="comment">// Can be used as: pow< 2 >(_1)</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">Exp</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Arg</span><span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">make_expr</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">function</span> <span class="comment">// Tag type</span> |
| <span class="special">,</span> <span class="identifier">pow_fun</span><span class="special"><</span><span class="identifier">Exp</span><span class="special">></span> <span class="comment">// First child (by value)</span> |
| <span class="special">,</span> <span class="identifier">Arg</span> <span class="keyword">const</span> <span class="special">&</span> <span class="comment">// Second child (by reference)</span> |
| <span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> |
| <span class="identifier">pow</span><span class="special">(</span><span class="identifier">Arg</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">arg</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">make_expr</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">function</span><span class="special">>(</span> |
| <span class="identifier">pow_fun</span><span class="special"><</span><span class="identifier">Exp</span><span class="special">>()</span> <span class="comment">// First child (by value)</span> |
| <span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">arg</span><span class="special">)</span> <span class="comment">// Second child (by reference)</span> |
| <span class="special">);</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| There are some things to notice about the above code. We use <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">make_expr</span><span class="special"><></span></code> |
| to calculate the return type. The first template parameter is the tag type |
| for the expression node we're building -- in this case, <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">function</span></code>, |
| which is the tag type Proto uses for function call expressions. |
| </p> |
| <p> |
| Subsequent template parameters to <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">make_expr</span><span class="special"><></span></code> represent children nodes. If a |
| child type is not already a Proto expression, it is made into a terminal |
| with <code class="computeroutput"><a class="link" href="../boost/proto/as_child_id1386369.html" title="Function as_child">proto::as_child()</a></code>. A type such as <code class="computeroutput"><span class="identifier">pow_fun</span><span class="special"><</span><span class="identifier">Exp</span><span class="special">></span></code> |
| results in terminal that is held by value, whereas a type like <code class="computeroutput"><span class="identifier">Arg</span> <span class="keyword">const</span> <span class="special">&</span></code> (note the reference) indicates that |
| the result should be held by reference. |
| </p> |
| <p> |
| In the function body is the runtime invocation of <code class="computeroutput"><a class="link" href="../boost/proto/make_expr_id1362445.html" title="Function make_expr">proto::make_expr()</a></code>. |
| It closely mirrors the return type calculation. <code class="computeroutput"><a class="link" href="../boost/proto/make_expr_id1362445.html" title="Function make_expr">proto::make_expr()</a></code> |
| requires you to specify the node's tag type as a template parameter. The |
| arguments to the function become the node's children. When a child should |
| be stored by value, nothing special needs to be done. When a child should |
| be stored by reference, you must use the <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">()</span></code> function to wrap the argument. Without |
| this extra information, the <code class="computeroutput"><a class="link" href="../boost/proto/make_expr_id1362445.html" title="Function make_expr">proto::make_expr()</a></code> |
| function couldn't know whether to store a child by value or by reference. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.front_end.adding_members_by_extending_expressions"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.adding_members_by_extending_expressions" title="Adding Members by Extending Expressions">Adding |
| Members by Extending Expressions</a> |
| </h4></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.front_end.adding_members_by_extending_expressions.domains">Domains</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.front_end.adding_members_by_extending_expressions.extends">The |
| <code class="literal">extends<></code> Expression Wrapper</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.front_end.adding_members_by_extending_expressions.expression_generators">Expression |
| Generators</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.front_end.adding_members_by_extending_expressions.inhibiting_overloads">Controlling |
| Operator Overloads</a></span></dt> |
| </dl></div> |
| <p> |
| In this section, we'll see how to associate Proto expressions with a <span class="emphasis"><em>domain</em></span>, |
| how to add members to expressions within a domain, and how to control which |
| operators are overloaded in a domain. |
| </p> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.front_end.adding_members_by_extending_expressions.domains"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.adding_members_by_extending_expressions.domains" title="Domains">Domains</a> |
| </h5></div></div></div> |
| <p> |
| In the <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.hello_calculator" title="Hello Calculator">Hello |
| Calculator</a> section, we looked into making calculator expressions |
| directly usable as lambda expressions in calls to STL algorithms, as |
| below: |
| </p> |
| <pre class="programlisting"><span class="keyword">double</span> <span class="identifier">data</span><span class="special">[]</span> <span class="special">=</span> <span class="special">{</span><span class="number">1.</span><span class="special">,</span> <span class="number">2.</span><span class="special">,</span> <span class="number">3.</span><span class="special">,</span> <span class="number">4.</span><span class="special">};</span> |
| |
| <span class="comment">// Use the calculator DSEL to square each element ... HOW?</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">transform</span><span class="special">(</span> <span class="identifier">data</span><span class="special">,</span> <span class="identifier">data</span> <span class="special">+</span> <span class="number">4</span><span class="special">,</span> <span class="identifier">data</span><span class="special">,</span> <span class="identifier">_1</span> <span class="special">*</span> <span class="identifier">_1</span> <span class="special">);</span> |
| </pre> |
| <p> |
| The difficulty, if you recall, was that by default Proto expressions |
| don't have interesting behaviors of their own. They're just trees. In |
| particular, the expression <code class="computeroutput"><span class="identifier">_1</span> |
| <span class="special">*</span> <span class="identifier">_1</span></code> |
| won't have an <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code> |
| that takes a double and returns a double like <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">transform</span><span class="special">()</span></code> expects -- unless we give it one. To |
| make this work, we needed to define an expression wrapper type that defined |
| the <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code> |
| member function, and we needed to associate the wrapper with the calculator |
| <span class="emphasis"><em>domain</em></span>. |
| </p> |
| <p> |
| In Proto, the term <span class="emphasis"><em>domain</em></span> refers to a type that |
| associates expressions in that domain to an expression <span class="emphasis"><em>generator</em></span>. |
| The generator is just a function object that accepts an expression and |
| does something to it, like wrapping it in an expression wrapper. |
| </p> |
| <p> |
| You can also use a domain to associate expressions with a grammar. When |
| you specify a domain's grammar, Proto ensures that all the expressions |
| it generates in that domain conform to the domain's grammar. It does |
| that by disabling any operator overloads that would create invalid expressions. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.front_end.adding_members_by_extending_expressions.extends"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.adding_members_by_extending_expressions.extends" title="The extends<> Expression Wrapper">The |
| <code class="literal">extends<></code> Expression Wrapper</a> |
| </h5></div></div></div> |
| <p> |
| The first step to giving your calculator expressions extra behaviors |
| is to define a calculator domain. All expressions within the calculator |
| domain will be imbued with calculator-ness, as we'll see. |
| </p> |
| <pre class="programlisting"><span class="comment">// A type to be used as a domain tag (to be defined below)</span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_domain</span><span class="special">;</span> |
| </pre> |
| <p> |
| We use this domain type when extending the <code class="computeroutput"><a class="link" href="../boost/proto/expr.html" title="Struct template expr">proto::expr<></a></code> |
| type, which we do with the <code class="computeroutput"><a class="link" href="../boost/proto/extends.html" title="Struct template extends">proto::extends<></a></code> |
| class template. Here is our expression wrapper, which imbues an expression |
| with calculator-ness. It is described below. |
| </p> |
| <pre class="programlisting"><span class="comment">// The calculator<> expression wrapper makes expressions</span> |
| <span class="comment">// function objects.</span> |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Expr</span> <span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">calculator</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">calculator</span><span class="special"><</span> <span class="identifier">Expr</span> <span class="special">>,</span> <span class="identifier">calculator_domain</span> <span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">calculator</span><span class="special"><</span> <span class="identifier">Expr</span> <span class="special">>,</span> <span class="identifier">calculator_domain</span> <span class="special">></span> |
| <span class="identifier">base_type</span><span class="special">;</span> |
| |
| <span class="identifier">calculator</span><span class="special">(</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span> <span class="special">=</span> <span class="identifier">Expr</span><span class="special">()</span> <span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">base_type</span><span class="special">(</span> <span class="identifier">expr</span> <span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="comment">// This is usually needed because by default, the compiler-</span> |
| <span class="comment">// generated assignment operator hides extends<>::operator=</span> |
| <span class="identifier">BOOST_PROTO_EXTENDS_USING_ASSIGN</span><span class="special">(</span><span class="identifier">calculator</span><span class="special">)</span> |
| |
| <span class="keyword">typedef</span> <span class="keyword">double</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="comment">// Hide base_type::operator() by defining our own which</span> |
| <span class="comment">// evaluates the calculator expression with a calculator context.</span> |
| <span class="identifier">result_type</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="keyword">double</span> <span class="identifier">d1</span> <span class="special">=</span> <span class="number">0.0</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">d2</span> <span class="special">=</span> <span class="number">0.0</span> <span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="comment">// As defined in the Hello Calculator section.</span> |
| <span class="identifier">calculator_context</span> <span class="identifier">ctx</span><span class="special">;</span> |
| |
| <span class="comment">// ctx.args is a vector<double> that holds the values</span> |
| <span class="comment">// with which we replace the placeholders (e.g., _1 and _2)</span> |
| <span class="comment">// in the expression.</span> |
| <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">args</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span> <span class="identifier">d1</span> <span class="special">);</span> <span class="comment">// _1 gets the value of d1</span> |
| <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">args</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span> <span class="identifier">d2</span> <span class="special">);</span> <span class="comment">// _2 gets the value of d2</span> |
| |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span> <span class="special">);</span> <span class="comment">// evaluate the expression</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| We want calculator expressions to be function objects, so we have to |
| define an <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code> |
| that takes and returns doubles. The <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><></span></code> wrapper above does that with |
| the help of the <code class="computeroutput"><a class="link" href="../boost/proto/extends.html" title="Struct template extends">proto::extends<></a></code> |
| template. The first template to <code class="computeroutput"><a class="link" href="../boost/proto/extends.html" title="Struct template extends">proto::extends<></a></code> |
| parameter is the expression type we are extending. The second is the |
| type of the wrapped expression. The third parameter is the domain that |
| this wrapper is associated with. A wrapper type like <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><></span></code> that inherits from <code class="computeroutput"><a class="link" href="../boost/proto/extends.html" title="Struct template extends">proto::extends<></a></code> behaves just like |
| the expression type it has extended, with any additional behaviors you |
| choose to give it. |
| </p> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"> |
| <p> |
| <span class="bold"><strong>Why not just inherit from <code class="literal">proto::expr<></code>?</strong></span> |
| </p> |
| <p> |
| You might be thinking that this expression extension business is unnecessarily |
| complicated. After all, isn't this why C++ supports inheritance? Why |
| can't <code class="literal">calculator<Expr></code> just inherit from |
| <code class="literal">Expr</code> directly? The reason is because <code class="literal">Expr</code>, |
| which presumably is an instantiation of <code class="computeroutput"><a class="link" href="../boost/proto/expr.html" title="Struct template expr">proto::expr<></a></code>, |
| has expression template-building operator overloads that will be incorrect |
| for derived types. They will store <code class="computeroutput"><span class="special">*</span><span class="keyword">this</span></code> by reference to <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">expr</span><span class="special"><></span></code>, effectively slicing off any |
| derived parts. <code class="computeroutput"><a class="link" href="../boost/proto/extends.html" title="Struct template extends">proto::extends<></a></code> |
| gives your derived types operator overloads that don't slice off your |
| additional members. |
| </p> |
| </td></tr> |
| </table></div> |
| <p> |
| Although not strictly necessary in this case, we bring <code class="computeroutput"><span class="identifier">extends</span><span class="special"><>::</span><span class="keyword">operator</span><span class="special">=</span></code> |
| into scope with the <code class="computeroutput"><span class="identifier">BOOST_PROTO_EXTENDS_USING_ASSIGN</span><span class="special">()</span></code> macro. This is really only necessary |
| if you want expressions like <code class="computeroutput"><span class="identifier">_1</span> |
| <span class="special">=</span> <span class="number">3</span></code> |
| to create a lazily evaluated assignment. <code class="computeroutput"><a class="link" href="../boost/proto/extends.html" title="Struct template extends">proto::extends<></a></code> |
| defines the appropriate <code class="computeroutput"><span class="keyword">operator</span><span class="special">=</span></code> for you, but the compiler-generated |
| <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><>::</span><span class="keyword">operator</span><span class="special">=</span></code> |
| will hide it unless you make it available with the macro. |
| </p> |
| <p> |
| Note that in the implementation of <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><>::</span><span class="keyword">operator</span><span class="special">()</span></code>, we evaluate the expression with the |
| <code class="computeroutput"><span class="identifier">calculator_context</span></code> we |
| defined earlier. As we saw before, the context is what gives the operators |
| their meaning. In the case of the calculator, the context is also what |
| defines the meaning of the placeholder terminals. |
| </p> |
| <p> |
| Now that we have defined the <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><></span></code> expression wrapper, we need to |
| wrap the placeholders to imbue them with calculator-ness: |
| </p> |
| <pre class="programlisting"><span class="identifier">calculator</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="number">0</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> <span class="special">></span> <span class="keyword">const</span> <span class="identifier">_1</span><span class="special">;</span> |
| <span class="identifier">calculator</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="number">1</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> <span class="special">></span> <span class="keyword">const</span> <span class="identifier">_2</span><span class="special">;</span> |
| </pre> |
| <a name="boost_proto.users_guide.front_end.adding_members_by_extending_expressions.extends.retaining_pod_ness_with__literal_boost_proto_extends____literal_"></a><h6> |
| <a name="boost_proto.users_guide.front_end.adding_members_by_extending_expressions.extends.retaining_pod_ness_with__literal_boost_proto_extends____literal_-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.front_end.adding_members_by_extending_expressions.extends.retaining_pod_ness_with__literal_boost_proto_extends____literal_">Retaining |
| POD-ness with <code class="literal">BOOST_PROTO_EXTENDS()</code></a> |
| </h6> |
| <p> |
| To use <code class="computeroutput"><a class="link" href="../boost/proto/extends.html" title="Struct template extends">proto::extends<></a></code>, your extension type |
| must derive from <code class="computeroutput"><a class="link" href="../boost/proto/extends.html" title="Struct template extends">proto::extends<></a></code>. |
| Unfortunately, that means that your extension type is no longer POD and |
| its instances cannot be <span class="emphasis"><em>statically initialized</em></span>. |
| (See the <a class="link" href="appendices.html#boost_proto.appendices.rationale.static_initialization" title="Static Initialization">Static |
| Initialization</a> section in the <a class="link" href="appendices.html#boost_proto.appendices.rationale" title="Appendix C: Rationale">Rationale</a> |
| appendix for why this matters.) In particular, as defined above, the |
| global placeholder objects <code class="computeroutput"><span class="identifier">_1</span></code> |
| and <code class="computeroutput"><span class="identifier">_2</span></code> will need to be |
| initialized at runtime, which could lead to subtle order of initialization |
| bugs. |
| </p> |
| <p> |
| There is another way to make an expression extension that doesn't sacrifice |
| POD-ness : the <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS.html" title="Macro BOOST_PROTO_EXTENDS">BOOST_PROTO_EXTENDS</a></code>()</code> |
| macro. You can use it much like you use <code class="computeroutput"><a class="link" href="../boost/proto/extends.html" title="Struct template extends">proto::extends<></a></code>. |
| We can use <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS.html" title="Macro BOOST_PROTO_EXTENDS">BOOST_PROTO_EXTENDS</a></code>()</code> |
| to keep <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><></span></code> |
| a POD and our placeholders statically initialized. |
| </p> |
| <pre class="programlisting"><span class="comment">// The calculator<> expression wrapper makes expressions</span> |
| <span class="comment">// function objects.</span> |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Expr</span> <span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">calculator</span> |
| <span class="special">{</span> |
| <span class="comment">// Use BOOST_PROTO_EXTENDS() instead of proto::extends<> to</span> |
| <span class="comment">// make this type a Proto expression extension.</span> |
| <span class="identifier">BOOST_PROTO_EXTENDS</span><span class="special">(</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">calculator</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>,</span> <span class="identifier">calculator_domain</span><span class="special">)</span> |
| |
| <span class="keyword">typedef</span> <span class="keyword">double</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">result_type</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="keyword">double</span> <span class="identifier">d1</span> <span class="special">=</span> <span class="number">0.0</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">d2</span> <span class="special">=</span> <span class="number">0.0</span> <span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="comment">/* ... as before ... */</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| With the new <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><></span></code> type, we can redefine our placeholders |
| to be statically initialized: |
| </p> |
| <pre class="programlisting"><span class="identifier">calculator</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="number">0</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> <span class="special">></span> <span class="keyword">const</span> <span class="identifier">_1</span> <span class="special">=</span> <span class="special">{{{}}};</span> |
| <span class="identifier">calculator</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="number">1</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> <span class="special">></span> <span class="keyword">const</span> <span class="identifier">_2</span> <span class="special">=</span> <span class="special">{{{}}};</span> |
| </pre> |
| <p> |
| We need to make one additional small change to accommodate the POD-ness |
| of our expression extension, which we'll describe below in the section |
| on expression generators. |
| </p> |
| <p> |
| What does <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS.html" title="Macro BOOST_PROTO_EXTENDS">BOOST_PROTO_EXTENDS</a></code>()</code> |
| do? It defines a data member of the expression type being extended; some |
| nested typedefs that Proto requires; <code class="computeroutput"><span class="keyword">operator</span><span class="special">=</span></code>, <code class="computeroutput"><span class="keyword">operator</span><span class="special">[]</span></code> and <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code> overloads for building expression templates; |
| and a nested <code class="computeroutput"><span class="identifier">result</span><span class="special"><></span></code> |
| template for calculating the return type of <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code>. In this case, however, the <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code> |
| overloads and the <code class="computeroutput"><span class="identifier">result</span><span class="special"><></span></code> template are not needed because |
| we are defining our own <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code> in the <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><></span></code> type. Proto provides additional |
| macros for finer control over which member functions are defined. We |
| could improve our <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><></span></code> type as follows: |
| </p> |
| <pre class="programlisting"><span class="comment">// The calculator<> expression wrapper makes expressions</span> |
| <span class="comment">// function objects.</span> |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Expr</span> <span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">calculator</span> |
| <span class="special">{</span> |
| <span class="comment">// Use BOOST_PROTO_BASIC_EXTENDS() instead of proto::extends<> to</span> |
| <span class="comment">// make this type a Proto expression extension:</span> |
| <span class="identifier">BOOST_PROTO_BASIC_EXTENDS</span><span class="special">(</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">calculator</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>,</span> <span class="identifier">calculator_domain</span><span class="special">)</span> |
| |
| <span class="comment">// Define operator[] to build expression templates:</span> |
| <span class="identifier">BOOST_PROTO_EXTENDS_SUBSCRIPT</span><span class="special">()</span> |
| |
| <span class="comment">// Define operator= to build expression templates:</span> |
| <span class="identifier">BOOST_PROTO_EXTENDS_ASSIGN</span><span class="special">()</span> |
| |
| <span class="keyword">typedef</span> <span class="keyword">double</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">result_type</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="keyword">double</span> <span class="identifier">d1</span> <span class="special">=</span> <span class="number">0.0</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">d2</span> <span class="special">=</span> <span class="number">0.0</span> <span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="comment">/* ... as before ... */</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| Notice that we are now using <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_BASIC_EXTENDS.html" title="Macro BOOST_PROTO_BASIC_EXTENDS">BOOST_PROTO_BASIC_EXTENDS</a></code>()</code> |
| instead of <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS.html" title="Macro BOOST_PROTO_EXTENDS">BOOST_PROTO_EXTENDS</a></code>()</code>. |
| This just adds the data member and the nested typedefs but not any of |
| the overloaded operators. Those are added separately with <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS_ASSIGN.html" title="Macro BOOST_PROTO_EXTENDS_ASSIGN">BOOST_PROTO_EXTENDS_ASSIGN</a></code>()</code> |
| and <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS_SUBSCRIPT.html" title="Macro BOOST_PROTO_EXTENDS_SUBSCRIPT">BOOST_PROTO_EXTENDS_SUBSCRIPT</a></code>()</code>. |
| We are leaving out the function call operator and the nested <code class="computeroutput"><span class="identifier">result</span><span class="special"><></span></code> |
| template that could have been defined with Proto's <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS_FUNCTION.html" title="Macro BOOST_PROTO_EXTENDS_FUNCTION">BOOST_PROTO_EXTENDS_FUNCTION</a></code>()</code> |
| macro. |
| </p> |
| <p> |
| In summary, here are the macros you can use to define expression extensions, |
| and a brief description of each. |
| </p> |
| <div class="table"> |
| <a name="id2298740"></a><p class="title"><b>Table 16.2. Expression Extension Macros</b></p> |
| <div class="table-contents"><table class="table" summary="Expression Extension Macros"> |
| <colgroup> |
| <col> |
| <col> |
| </colgroup> |
| <thead><tr> |
| <th> |
| <p> |
| Macro |
| </p> |
| </th> |
| <th> |
| <p> |
| Purpose |
| </p> |
| </th> |
| </tr></thead> |
| <tbody> |
| <tr> |
| <td> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_BASIC_EXTENDS.html" title="Macro BOOST_PROTO_BASIC_EXTENDS">BOOST_PROTO_BASIC_EXTENDS</a></code><span class="special">(</span> |
| <em class="replaceable"><code>expression</code></em> |
| <span class="special">,</span> <em class="replaceable"><code>extension</code></em> |
| <span class="special">,</span> <em class="replaceable"><code>domain</code></em> |
| <span class="special">)</span></pre> |
| <p> |
| </p> |
| </td> |
| <td> |
| <p> |
| Defines a data member of type <code class="computeroutput"><em class="replaceable"><code>expression</code></em></code> |
| and some nested typedefs that Proto requires. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS_ASSIGN.html" title="Macro BOOST_PROTO_EXTENDS_ASSIGN">BOOST_PROTO_EXTENDS_ASSIGN</a></code>()</code> |
| </p> |
| </td> |
| <td> |
| <p> |
| Defines <code class="computeroutput"><span class="keyword">operator</span><span class="special">=</span></code>. Only valid when preceded |
| by <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_BASIC_EXTENDS.html" title="Macro BOOST_PROTO_BASIC_EXTENDS">BOOST_PROTO_BASIC_EXTENDS</a></code>()</code>. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS_SUBSCRIPT.html" title="Macro BOOST_PROTO_EXTENDS_SUBSCRIPT">BOOST_PROTO_EXTENDS_SUBSCRIPT</a></code>()</code> |
| </p> |
| </td> |
| <td> |
| <p> |
| Defines <code class="computeroutput"><span class="keyword">operator</span><span class="special">[]</span></code>. Only valid when preceded |
| by <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_BASIC_EXTENDS.html" title="Macro BOOST_PROTO_BASIC_EXTENDS">BOOST_PROTO_BASIC_EXTENDS</a></code>()</code>. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS_FUNCTION.html" title="Macro BOOST_PROTO_EXTENDS_FUNCTION">BOOST_PROTO_EXTENDS_FUNCTION</a></code>()</code> |
| </p> |
| </td> |
| <td> |
| <p> |
| Defines <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code> and a nested <code class="computeroutput"><span class="identifier">result</span><span class="special"><></span></code> |
| template for return type calculation. Only valid when preceded |
| by <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_BASIC_EXTENDS.html" title="Macro BOOST_PROTO_BASIC_EXTENDS">BOOST_PROTO_BASIC_EXTENDS</a></code>()</code>. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS.html" title="Macro BOOST_PROTO_EXTENDS">BOOST_PROTO_EXTENDS</a></code><span class="special">(</span> |
| <em class="replaceable"><code>expression</code></em> |
| <span class="special">,</span> <em class="replaceable"><code>extension</code></em> |
| <span class="special">,</span> <em class="replaceable"><code>domain</code></em> |
| <span class="special">)</span></pre> |
| <p> |
| </p> |
| </td> |
| <td> |
| <p> |
| Equivalent to: |
| </p> |
| <pre class="programlisting"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_BASIC_EXTENDS.html" title="Macro BOOST_PROTO_BASIC_EXTENDS">BOOST_PROTO_BASIC_EXTENDS</a></code><span class="special">(</span><em class="replaceable"><code>expression</code></em><span class="special">,</span> <em class="replaceable"><code>extension</code></em><span class="special">,</span> <em class="replaceable"><code>domain</code></em><span class="special">)</span> |
| |
| <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS_ASSIGN.html" title="Macro BOOST_PROTO_EXTENDS_ASSIGN">BOOST_PROTO_EXTENDS_ASSIGN</a></code>()</code> |
| |
| <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS_SUBSCRIPT.html" title="Macro BOOST_PROTO_EXTENDS_SUBSCRIPT">BOOST_PROTO_EXTENDS_SUBSCRIPT</a></code>()</code> |
| |
| <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS_FUNCTION.html" title="Macro BOOST_PROTO_EXTENDS_FUNCTION">BOOST_PROTO_EXTENDS_FUNCTION</a></code>()</code></pre> |
| <p> |
| </p> |
| </td> |
| </tr> |
| </tbody> |
| </table></div> |
| </div> |
| <br class="table-break"><div class="warning"><table border="0" summary="Warning"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Warning]" src="../../../doc/src/images/warning.png"></td> |
| <th align="left">Warning</th> |
| </tr> |
| <tr><td align="left" valign="top"> |
| <p> |
| <span class="bold"><strong>Argument-Dependent Lookup and <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS.html" title="Macro BOOST_PROTO_EXTENDS">BOOST_PROTO_EXTENDS</a></code>()</code></strong></span> |
| </p> |
| <p> |
| Proto's operator overloads are defined in the <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span></code> |
| namespace and are found by argument-dependent lookup (ADL). This usually |
| just works because expressions are made up of types that live in the |
| <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span></code> namespace. However, sometimes |
| when you use <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS.html" title="Macro BOOST_PROTO_EXTENDS">BOOST_PROTO_EXTENDS</a></code>()</code> |
| that is not the case. Consider: |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">my_complex</span> |
| <span class="special">{</span> |
| <span class="identifier">BOOST_PROTO_EXTENDS</span><span class="special">(</span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">complex</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">,</span> <span class="identifier">my_complex</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">default_domain</span> |
| <span class="special">)</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="identifier">my_complex</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="identifier">c0</span><span class="special">,</span> <span class="identifier">c1</span><span class="special">;</span> |
| |
| <span class="identifier">c0</span> <span class="special">+</span> <span class="identifier">c1</span><span class="special">;</span> <span class="comment">// ERROR: operator+ not found</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| <p> |
| The problem has to do with how argument-dependent lookup works. The |
| type <code class="computeroutput"><span class="identifier">my_complex</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span></code> |
| is not associated in any way with the <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span></code> |
| namespace, so the operators defined there are not considered. (Had |
| we inherited from <code class="computeroutput"><a class="link" href="../boost/proto/extends.html" title="Struct template extends">proto::extends<></a></code> |
| instead of used <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS.html" title="Macro BOOST_PROTO_EXTENDS">BOOST_PROTO_EXTENDS</a></code>()</code>, |
| we would have avoided the problem because inheriting from a type in |
| <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span></code> namespace is enough to get |
| ADL to kick in.) |
| </p> |
| <p> |
| So what can we do? By adding an extra dummy template parameter that |
| defaults to a type in the <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span></code> |
| namespace, we can trick ADL into finding the right operator overloads. |
| The solution looks like this: |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">Dummy</span> <span class="special">=</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">is_proto_expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">my_complex</span> |
| <span class="special">{</span> |
| <span class="identifier">BOOST_PROTO_EXTENDS</span><span class="special">(</span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">complex</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">,</span> <span class="identifier">my_complex</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">default_domain</span> |
| <span class="special">)</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="identifier">my_complex</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="identifier">c0</span><span class="special">,</span> <span class="identifier">c1</span><span class="special">;</span> |
| |
| <span class="identifier">c0</span> <span class="special">+</span> <span class="identifier">c1</span><span class="special">;</span> <span class="comment">// OK, operator+ found now!</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| <p> |
| The type <code class="computeroutput"><a class="link" href="../boost/proto/is_proto_expr.html" title="Struct is_proto_expr">proto::is_proto_expr</a></code> is nothing |
| but an empty struct, but by making it a template parameter we make |
| <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span></code> an associated namespace of |
| <code class="computeroutput"><span class="identifier">my_complex</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span></code>. |
| Now ADL can successfully find Proto's operator overloads. |
| </p> |
| </td></tr> |
| </table></div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.front_end.adding_members_by_extending_expressions.expression_generators"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.adding_members_by_extending_expressions.expression_generators" title="Expression Generators">Expression |
| Generators</a> |
| </h5></div></div></div> |
| <p> |
| The last thing that remains to be done is to tell Proto that it needs |
| to wrap all of our calculator expressions in our <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><></span></code> wrapper. We have already wrapped |
| the placeholders, but we want <span class="emphasis"><em>all</em></span> expressions that |
| involve the calculator placeholders to be calculators. We can do that |
| by specifying an expression generator when we define our <code class="computeroutput"><span class="identifier">calculator_domain</span></code>, as follows: |
| </p> |
| <pre class="programlisting"><span class="comment">// Define the calculator_domain we forward-declared above.</span> |
| <span class="comment">// Specify that all expression in this domain should be wrapped</span> |
| <span class="comment">// in the calculator<> expression wrapper.</span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_domain</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">generator</span><span class="special"><</span> <span class="identifier">calculator</span> <span class="special">></span> <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| The first template parameter to <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><></span></code> is the generator. "Generator" |
| is just a fancy name for a function object that accepts an expression |
| and does something to it. <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">generator</span><span class="special"><></span></code> is a very simple one --- it wraps |
| an expression in the wrapper you specify. <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><></span></code> inherits from its generator parameter, |
| so all domains are themselves function objects. |
| </p> |
| <p> |
| If we used <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_EXTENDS.html" title="Macro BOOST_PROTO_EXTENDS">BOOST_PROTO_EXTENDS</a></code>()</code> |
| to keep our expression extension type POD, then we need to use <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">pod_generator</span><span class="special"><></span></code> |
| instead of <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">generator</span><span class="special"><></span></code>, |
| as follows: |
| </p> |
| <pre class="programlisting"><span class="comment">// If calculator<> uses BOOST_PROTO_EXTENDS() instead of </span> |
| <span class="comment">// use proto::extends<>, use proto::pod_generator<> instead</span> |
| <span class="comment">// of proto::generator<>.</span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_domain</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">pod_generator</span><span class="special"><</span> <span class="identifier">calculator</span> <span class="special">></span> <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| After Proto has calculated a new expression type, it checks the domains |
| of the child expressions. They must match. Assuming they do, Proto creates |
| the new expression and passes it to <code class="computeroutput"><em class="replaceable"><code>Domain</code></em><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code> for any additional processing. If we |
| don't specify a generator, the new expression gets passed through unchanged. |
| But since we've specified a generator above, <code class="computeroutput"><span class="identifier">calculator_domain</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code> returns <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><></span></code> objects. |
| </p> |
| <p> |
| Now we can use calculator expressions as function objects to STL algorithms, |
| as follows: |
| </p> |
| <pre class="programlisting"><span class="keyword">double</span> <span class="identifier">data</span><span class="special">[]</span> <span class="special">=</span> <span class="special">{</span><span class="number">1.</span><span class="special">,</span> <span class="number">2.</span><span class="special">,</span> <span class="number">3.</span><span class="special">,</span> <span class="number">4.</span><span class="special">};</span> |
| |
| <span class="comment">// Use the calculator DSEL to square each element ... WORKS! :-)</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">transform</span><span class="special">(</span> <span class="identifier">data</span><span class="special">,</span> <span class="identifier">data</span> <span class="special">+</span> <span class="number">4</span><span class="special">,</span> <span class="identifier">data</span><span class="special">,</span> <span class="identifier">_1</span> <span class="special">*</span> <span class="identifier">_1</span> <span class="special">);</span> |
| </pre> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.front_end.adding_members_by_extending_expressions.inhibiting_overloads"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.adding_members_by_extending_expressions.inhibiting_overloads" title="Controlling Operator Overloads">Controlling |
| Operator Overloads</a> |
| </h5></div></div></div> |
| <p> |
| By default, Proto defines every possible operator overload for Protofied |
| expressions. This makes it simple to bang together a DSEL. In some cases, |
| however, the presence of Proto's promiscuous overloads can lead to confusion |
| or worse. When that happens, you'll have to disable some of Proto's overloaded |
| operators. That is done by defining the grammar for your domain and specifying |
| it as the second parameter of the <code class="computeroutput"><a class="link" href="../boost/proto/domain.html" title="Struct template domain">proto::domain<></a></code> |
| template. |
| </p> |
| <p> |
| In the <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.hello_calculator" title="Hello Calculator">Hello |
| Calculator</a> section, we saw an example of a Proto grammar, which |
| is repeated here: |
| </p> |
| <pre class="programlisting"><span class="comment">// Define the grammar of calculator expressions</span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_grammar</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span> <span class="identifier">calculator_grammar</span><span class="special">,</span> <span class="identifier">calculator_grammar</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">minus</span><span class="special"><</span> <span class="identifier">calculator_grammar</span><span class="special">,</span> <span class="identifier">calculator_grammar</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">multiplies</span><span class="special"><</span> <span class="identifier">calculator_grammar</span><span class="special">,</span> <span class="identifier">calculator_grammar</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">divides</span><span class="special"><</span> <span class="identifier">calculator_grammar</span><span class="special">,</span> <span class="identifier">calculator_grammar</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span> <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| We'll have much more to say about grammars in subsequent sections, but |
| for now, we'll just say that the <code class="computeroutput"><span class="identifier">calculator_grammar</span></code> |
| struct describes a subset of all expression types -- the subset that |
| comprise valid calculator expressions. We would like to prohibit Proto |
| from creating a calculator expression that does not conform to this grammar. |
| We do that by changing the definition of the <code class="computeroutput"><span class="identifier">calculator_domain</span></code> |
| struct. |
| </p> |
| <pre class="programlisting"><span class="comment">// Define the calculator_domain. Expressions in the calculator</span> |
| <span class="comment">// domain are wrapped in the calculator<> wrapper, and they must</span> |
| <span class="comment">// conform to the calculator_grammar:</span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_domain</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">generator</span><span class="special"><</span> <span class="identifier">calculator</span> <span class="special">>,</span> <span class="bold"><strong>calculator_grammar</strong></span> <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| The only new addition is <code class="computeroutput"><span class="identifier">calculator_grammar</span></code> |
| as the second template parameter to the <code class="computeroutput"><a class="link" href="../boost/proto/domain.html" title="Struct template domain">proto::domain<></a></code> |
| template. That has the effect of disabling any of Proto's operator overloads |
| that would create an invalid calculator expression. |
| </p> |
| <p> |
| Another common use for this feature would be to disable Proto's unary |
| <code class="computeroutput"><span class="keyword">operator</span><span class="special">&</span></code> |
| overload. It may be surprising for users of your DSEL that they cannot |
| take the address of their expressions! You can very easily disable Proto's |
| unary <code class="computeroutput"><span class="keyword">operator</span><span class="special">&</span></code> |
| overload for your domain with a very simple grammar, as below: |
| </p> |
| <pre class="programlisting"><span class="comment">// For expressions in my_domain, disable Proto's</span> |
| <span class="comment">// unary address-of operator.</span> |
| <span class="keyword">struct</span> <span class="identifier">my_domain</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">generator</span><span class="special"><</span> <span class="identifier">my_wrapper</span> <span class="special">></span> |
| <span class="comment">// A simple grammar that matches any expression that</span> |
| <span class="comment">// is not a unary address-of expression.</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">not_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">address_of</span><span class="special"><</span> <span class="identifier">_</span> <span class="special">></span> <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| The type <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">not_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">address_of</span><span class="special"><</span> |
| <span class="identifier">_</span> <span class="special">></span> |
| <span class="special">></span></code> is a very simple grammar |
| that matches all expressions except unary address-of expressions. In |
| the section describing Proto's intermediate form, we'll have much more |
| to say about grammars. |
| </p> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.front_end.define_operators"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.define_operators" title="Adapting Existing Types to Proto">Adapting |
| Existing Types to Proto</a> |
| </h4></div></div></div> |
| <p> |
| The preceding discussions of defining Proto front ends have all made a |
| big assumption: that you have the luxury of defining everything from scratch. |
| What happens if you have existing types, say a matrix type and a vector |
| type, that you would like to treat as if they were Proto terminals? Proto |
| usually trades only in its own expression types, but with <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_DEFINE_OPERATORS.html" title="Macro BOOST_PROTO_DEFINE_OPERATORS">BOOST_PROTO_DEFINE_OPERATORS</a></code>()</code>, |
| it can accomodate your custom terminal types, too. |
| </p> |
| <p> |
| Let's say, for instance, that you have the following types and that you |
| can't modify then to make them <span class="quote">“<span class="quote">native</span>”</span> Proto terminal types. |
| </p> |
| <pre class="programlisting"><span class="keyword">namespace</span> <span class="identifier">math</span> |
| <span class="special">{</span> |
| <span class="comment">// A matrix type ...</span> |
| <span class="keyword">struct</span> <span class="identifier">matrix</span> <span class="special">{</span> <span class="comment">/*...*/</span> <span class="special">};</span> |
| |
| <span class="comment">// A vector type ...</span> |
| <span class="keyword">struct</span> <span class="identifier">vector</span> <span class="special">{</span> <span class="comment">/*...*/</span> <span class="special">};</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| You can non-intrusively make objects of these types Proto terminals by |
| defining the proper operator overloads using <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_DEFINE_OPERATORS.html" title="Macro BOOST_PROTO_DEFINE_OPERATORS">BOOST_PROTO_DEFINE_OPERATORS</a></code>()</code>. |
| The basic procedure is as follows: |
| </p> |
| <div class="orderedlist"><ol class="orderedlist" type="1"> |
| <li class="listitem"> |
| Define a trait that returns true for your types and false for all others. |
| </li> |
| <li class="listitem"> |
| Reopen the namespace of your types and use <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_DEFINE_OPERATORS.html" title="Macro BOOST_PROTO_DEFINE_OPERATORS">BOOST_PROTO_DEFINE_OPERATORS</a></code>()</code> |
| to define a set of operator overloads, passing the name of the trait |
| as the first macro parameter, and the name of a Proto domain (e.g., |
| <code class="computeroutput"><a class="link" href="../boost/proto/default_domain.html" title="Struct default_domain">proto::default_domain</a></code>) |
| as the second. |
| </li> |
| </ol></div> |
| <p> |
| The following code demonstrates how it works. |
| </p> |
| <pre class="programlisting"><span class="keyword">namespace</span> <span class="identifier">math</span> |
| <span class="special">{</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">is_terminal</span> |
| <span class="special">:</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">false_</span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// OK, "matrix" is a custom terminal type</span> |
| <span class="keyword">template</span><span class="special"><></span> |
| <span class="keyword">struct</span> <span class="identifier">is_terminal</span><span class="special"><</span><span class="identifier">matrix</span><span class="special">></span> |
| <span class="special">:</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">true_</span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// OK, "vector" is a custom terminal type</span> |
| <span class="keyword">template</span><span class="special"><></span> |
| <span class="keyword">struct</span> <span class="identifier">is_terminal</span><span class="special"><</span><span class="identifier">vector</span><span class="special">></span> |
| <span class="special">:</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">true_</span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Define all the operator overloads to construct Proto</span> |
| <span class="comment">// expression templates, treating "matrix" and "vector"</span> |
| <span class="comment">// objects as if they were Proto terminals.</span> |
| <span class="identifier">BOOST_PROTO_DEFINE_OPERATORS</span><span class="special">(</span><span class="identifier">is_terminal</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">default_domain</span><span class="special">)</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| The invocation of the <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_DEFINE_OPERATORS.html" title="Macro BOOST_PROTO_DEFINE_OPERATORS">BOOST_PROTO_DEFINE_OPERATORS</a></code>()</code> |
| macro defines a complete set of operator overloads that treat <code class="computeroutput"><span class="identifier">matrix</span></code> and <code class="computeroutput"><span class="identifier">vector</span></code> |
| objects as if they were Proto terminals. And since the operators are defined |
| in the same namespace as the <code class="computeroutput"><span class="identifier">matrix</span></code> |
| and <code class="computeroutput"><span class="identifier">vector</span></code> types, the operators |
| will be found by argument-dependent lookup. With the code above, we can |
| now construct expression templates with matrices and vectors, as shown |
| below. |
| </p> |
| <pre class="programlisting"><span class="identifier">math</span><span class="special">::</span><span class="identifier">matrix</span> <span class="identifier">m1</span><span class="special">;</span> |
| <span class="identifier">math</span><span class="special">::</span><span class="identifier">vector</span> <span class="identifier">v1</span><span class="special">;</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">literal</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="identifier">i</span><span class="special">(</span><span class="number">0</span><span class="special">);</span> |
| |
| <span class="identifier">m1</span> <span class="special">*</span> <span class="number">1</span><span class="special">;</span> <span class="comment">// custom terminal and literals are OK</span> |
| <span class="identifier">m1</span> <span class="special">*</span> <span class="identifier">i</span><span class="special">;</span> <span class="comment">// custom terminal and Proto expressions are OK</span> |
| <span class="identifier">m1</span> <span class="special">*</span> <span class="identifier">v1</span><span class="special">;</span> <span class="comment">// two custom terminals are OK, too.</span> |
| </pre> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.front_end.code_repetition"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.code_repetition" title="Generating Repetitive Code with the Preprocessor">Generating |
| Repetitive Code with the Preprocessor</a> |
| </h4></div></div></div> |
| <p> |
| Sometimes as a DSEL designer, to make the lives of your users easy, you |
| have to make your own life hard. Giving your users natural and flexible |
| syntax often involves writing large numbers of repetitive function overloads. |
| It can be enough to give you repetitive stress injury! Before you hurt |
| yourself, check out the macros Proto provides for automating many repetitive |
| code-generation chores. |
| </p> |
| <p> |
| Imagine that we are writing a lambda DSEL, and we would like to enable |
| syntax for constructing temporary objects of any type using the following |
| syntax: |
| </p> |
| <pre class="programlisting"><span class="comment">// A lambda expression that takes two arguments and</span> |
| <span class="comment">// uses them to construct a temporary std::complex<></span> |
| <span class="identifier">construct</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">complex</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="special">>(</span> <span class="identifier">_1</span><span class="special">,</span> <span class="identifier">_2</span> <span class="special">)</span> |
| </pre> |
| <p> |
| For the sake of the discussion, imagine that we already have a function |
| object template <code class="computeroutput"><span class="identifier">construct_impl</span><span class="special"><></span></code> that accepts arguments and constructs |
| new objects from them. We would want the above lambda expression to be |
| equivalent to the following: |
| </p> |
| <pre class="programlisting"><span class="comment">// The above lambda expression should be roughly equivalent</span> |
| <span class="comment">// to the following:</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">make_expr</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">function</span><span class="special">>(</span> |
| <span class="identifier">construct_impl</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">complex</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="special">>()</span> <span class="comment">// The function to invoke lazily</span> |
| <span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">_1</span><span class="special">)</span> <span class="comment">// The first argument to the function</span> |
| <span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">_2</span><span class="special">)</span> <span class="comment">// The second argument to the function</span> |
| <span class="special">);</span> |
| </pre> |
| <p> |
| We can define our <code class="computeroutput"><span class="identifier">construct</span><span class="special">()</span></code> function template as follows: |
| </p> |
| <pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A0</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A1</span><span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">make_expr</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">function</span> |
| <span class="special">,</span> <span class="identifier">construct_impl</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">A0</span> <span class="keyword">const</span> <span class="special">&</span> |
| <span class="special">,</span> <span class="identifier">A1</span> <span class="keyword">const</span> <span class="special">&</span> |
| <span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> |
| <span class="identifier">construct</span><span class="special">(</span><span class="identifier">A0</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">a0</span><span class="special">,</span> <span class="identifier">A1</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">a1</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">make_expr</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">function</span><span class="special">>(</span> |
| <span class="identifier">construct_impl</span><span class="special"><</span><span class="identifier">T</span><span class="special">>()</span> |
| <span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">a0</span><span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">a1</span><span class="special">)</span> |
| <span class="special">);</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| This works for two arguments, but we would like it to work for any number |
| of arguments, up to ( <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_MAX_ARITY.html" title="Macro BOOST_PROTO_MAX_ARITY">BOOST_PROTO_MAX_ARITY</a></code></code> |
| - 1). (Why "- 1"? Because one child is taken up by the <code class="computeroutput"><span class="identifier">construct_impl</span><span class="special"><</span><span class="identifier">T</span><span class="special">>()</span></code> |
| terminal leaving room for only ( <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_MAX_ARITY.html" title="Macro BOOST_PROTO_MAX_ARITY">BOOST_PROTO_MAX_ARITY</a></code></code> |
| - 1) other children.) |
| </p> |
| <p> |
| For cases like this, Proto provides the <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_REPEAT.html" title="Macro BOOST_PROTO_REPEAT">BOOST_PROTO_REPEAT</a></code>()</code> |
| and <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_REPEAT_FROM_TO.html" title="Macro BOOST_PROTO_REPEAT_FROM_TO">BOOST_PROTO_REPEAT_FROM_TO</a></code>()</code> |
| macros. To use it, we turn the function definition above into a macro as |
| follows: |
| </p> |
| <pre class="programlisting"><span class="preprocessor">#define</span> <span class="identifier">M0</span><span class="special">(</span><span class="identifier">N</span><span class="special">,</span> <span class="identifier">typename_A</span><span class="special">,</span> <span class="identifier">A_const_ref</span><span class="special">,</span> <span class="identifier">A_const_ref_a</span><span class="special">,</span> <span class="identifier">ref_a</span><span class="special">)</span> <span class="special">\</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">typename_A</span><span class="special">(</span><span class="identifier">N</span><span class="special">)></span> <span class="special">\</span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">make_expr</span><span class="special"><</span> <span class="special">\</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">function</span> <span class="special">\</span> |
| <span class="special">,</span> <span class="identifier">construct_impl</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span> <span class="special">\</span> |
| <span class="special">,</span> <span class="identifier">A_const_ref</span><span class="special">(</span><span class="identifier">N</span><span class="special">)</span> <span class="special">\</span> |
| <span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="special">\</span> |
| <span class="identifier">construct</span><span class="special">(</span><span class="identifier">A_const_ref_a</span><span class="special">(</span><span class="identifier">N</span><span class="special">))</span> <span class="special">\</span> |
| <span class="special">{</span> <span class="special">\</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">make_expr</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">function</span><span class="special">>(</span> <span class="special">\</span> |
| <span class="identifier">construct_impl</span><span class="special"><</span><span class="identifier">T</span><span class="special">>()</span> <span class="special">\</span> |
| <span class="special">,</span> <span class="identifier">ref_a</span><span class="special">(</span><span class="identifier">N</span><span class="special">)</span> <span class="special">\</span> |
| <span class="special">);</span> <span class="special">\</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| Notice that we turned the function into a macro that takes 5 arguments. |
| The first is the current iteration number. The rest are the names of other |
| macros that generate different sequences. For instance, Proto passes as |
| the second parameter the name of a macro that will expand to <code class="computeroutput"><span class="keyword">typename</span> <span class="identifier">A0</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A1</span><span class="special">,</span> <span class="special">...</span></code>. |
| </p> |
| <p> |
| Now that we have turned our function into a macro, we can pass the macro |
| to <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_REPEAT_FROM_TO.html" title="Macro BOOST_PROTO_REPEAT_FROM_TO">BOOST_PROTO_REPEAT_FROM_TO</a></code>()</code>. |
| Proto will invoke it iteratively, generating all the function overloads |
| for us. |
| </p> |
| <pre class="programlisting"><span class="comment">// Generate overloads of construct() that accept from</span> |
| <span class="comment">// 1 to BOOST_PROTO_MAX_ARITY-1 arguments:</span> |
| <span class="identifier">BOOST_PROTO_REPEAT_FROM_TO</span><span class="special">(</span><span class="number">1</span><span class="special">,</span> <span class="identifier">BOOST_PROTO_MAX_ARITY</span><span class="special">,</span> <span class="identifier">M0</span><span class="special">)</span> |
| <span class="preprocessor">#undef</span> <span class="identifier">M0</span> |
| </pre> |
| <a name="boost_proto.users_guide.front_end.code_repetition.non_default_sequences"></a><h6> |
| <a name="boost_proto.users_guide.front_end.code_repetition.non_default_sequences-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.front_end.code_repetition.non_default_sequences">Non-Default |
| Sequences</a> |
| </h6> |
| <p> |
| As mentioned above, Proto passes as the last 4 arguments to your macro |
| the names of other macros that generate various sequences. The macros |
| <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_REPEAT.html" title="Macro BOOST_PROTO_REPEAT">BOOST_PROTO_REPEAT</a></code>()</code> |
| and <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_REPEAT_FROM_TO.html" title="Macro BOOST_PROTO_REPEAT_FROM_TO">BOOST_PROTO_REPEAT_FROM_TO</a></code>()</code> |
| select defaults for these parameters. If the defaults do not meet your |
| needs, you can use <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_REPEAT_EX.html" title="Macro BOOST_PROTO_REPEAT_EX">BOOST_PROTO_REPEAT_EX</a></code>()</code> |
| and <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_REPEAT_FROM_TO_EX.html" title="Macro BOOST_PROTO_REPEAT_FROM_TO_EX">BOOST_PROTO_REPEAT_FROM_TO_EX</a></code>()</code> |
| and pass different macros that generate different sequences. Proto defines |
| a number of such macros for use as parameters to <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_REPEAT_EX.html" title="Macro BOOST_PROTO_REPEAT_EX">BOOST_PROTO_REPEAT_EX</a></code>()</code> |
| and <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_REPEAT_FROM_TO_EX.html" title="Macro BOOST_PROTO_REPEAT_FROM_TO_EX">BOOST_PROTO_REPEAT_FROM_TO_EX</a></code>()</code>. |
| Check the reference section for <code class="computeroutput"><a class="link" href="reference.html#header.boost.proto.repeat_hpp" title="Header <boost/proto/repeat.hpp>">boost/proto/repeat.hpp</a></code> |
| for all the details. |
| </p> |
| <p> |
| Also, check out <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_LOCAL_ITERATE.html" title="Macro BOOST_PROTO_LOCAL_ITERATE">BOOST_PROTO_LOCAL_ITERATE</a></code>()</code>. |
| It works similarly to <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_REPEAT.html" title="Macro BOOST_PROTO_REPEAT">BOOST_PROTO_REPEAT</a></code>()</code> |
| and friends, but it can be easier to use when you want to change one macro |
| argument and accept defaults for the others. |
| </p> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="boost_proto.users_guide.intermediate_form"></a><a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form" title="Intermediate Form: Understanding and Introspecting Expressions">Intermediate |
| Form: Understanding and Introspecting Expressions</a> |
| </h3></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.intermediate_form.left_right_child">Accessing |
| Parts of an Expression</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.intermediate_form.deep_copying_expressions">Deep-copying |
| Expressions</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.intermediate_form.debugging_expressions">Debugging |
| Expressions</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.intermediate_form.tags_and_metafunctions">Operator |
| Tags and Metafunctions</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.intermediate_form.expressions_as_fusion_sequences">Expressions |
| as Fusion Sequences</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.intermediate_form.expression_introspection">Expression |
| Introspection: Defining a Grammar</a></span></dt> |
| </dl></div> |
| <p> |
| By now, you know a bit about how to build a front-end for your DSEL "compiler" |
| -- you can define terminals and functions that generate expression templates. |
| But we haven't said anything about the expression templates themselves. What |
| do they look like? What can you do with them? In this section we'll see. |
| </p> |
| <a name="boost_proto.users_guide.intermediate_form.the__literal_expr_lt__gt___literal__type"></a><h5> |
| <a name="boost_proto.users_guide.intermediate_form.the__literal_expr_lt__gt___literal__type-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.the__literal_expr_lt__gt___literal__type">The |
| <code class="literal">expr<></code> Type</a> |
| </h5> |
| <p> |
| All Proto expressions are an instantiation of a template called <code class="computeroutput"><a class="link" href="../boost/proto/expr.html" title="Struct template expr">proto::expr<></a></code> (or a wrapper around |
| such an instantiation). When we define a terminal as below, we are really |
| initializing an instance of the <code class="computeroutput"><a class="link" href="../boost/proto/expr.html" title="Struct template expr">proto::expr<></a></code> |
| template. |
| </p> |
| <pre class="programlisting"><span class="comment">// Define a placeholder type</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">I</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">placeholder</span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Define the Protofied placeholder terminal</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="number">0</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">_1</span> <span class="special">=</span> <span class="special">{{}};</span> |
| </pre> |
| <p> |
| The actual type of <code class="computeroutput"><span class="identifier">_1</span></code> looks |
| like this: |
| </p> |
| <pre class="programlisting"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">expr</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">term</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="number">0</span><span class="special">></span> <span class="special">>,</span> <span class="number">0</span> <span class="special">></span> |
| </pre> |
| <p> |
| The <code class="computeroutput"><a class="link" href="../boost/proto/expr.html" title="Struct template expr">proto::expr<></a></code> template is the most |
| important type in Proto. Although you will rarely need to deal with it directly, |
| it's always there behind the scenes holding your expression trees together. |
| In fact, <code class="computeroutput"><a class="link" href="../boost/proto/expr.html" title="Struct template expr">proto::expr<></a></code> <span class="emphasis"><em>is</em></span> |
| the expression tree -- branches, leaves and all. |
| </p> |
| <p> |
| The <code class="computeroutput"><a class="link" href="../boost/proto/expr.html" title="Struct template expr">proto::expr<></a></code> template makes up the |
| nodes in expression trees. The first template parameter is the node type; |
| in this case, <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span></code>. |
| That means that <code class="computeroutput"><span class="identifier">_1</span></code> is a leaf-node |
| in the expression tree. The second template parameter is a list of child |
| types, or in the case of terminals, the terminal's value type. Terminals |
| will always have only one type in the type list. The last parameter is the |
| arity of the expression. Terminals have arity 0, unary expressions have arity |
| 1, etc. |
| </p> |
| <p> |
| The <code class="computeroutput"><a class="link" href="../boost/proto/expr.html" title="Struct template expr">proto::expr<></a></code> struct is defined as |
| follows: |
| </p> |
| <pre class="programlisting"><span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Tag</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Args</span><span class="special">,</span> <span class="keyword">long</span> <span class="identifier">Arity</span> <span class="special">=</span> <span class="identifier">Args</span><span class="special">::</span><span class="identifier">arity</span> <span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">expr</span><span class="special">;</span> |
| |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Tag</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Args</span> <span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">expr</span><span class="special"><</span> <span class="identifier">Tag</span><span class="special">,</span> <span class="identifier">Args</span><span class="special">,</span> <span class="number">1</span> <span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">typename</span> <span class="identifier">Args</span><span class="special">::</span><span class="identifier">child0</span> <span class="identifier">proto_child0</span><span class="special">;</span> |
| <span class="identifier">proto_child0</span> <span class="identifier">child0</span><span class="special">;</span> |
| <span class="comment">// ...</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| The <code class="computeroutput"><a class="link" href="../boost/proto/expr.html" title="Struct template expr">proto::expr<></a></code> struct does not define |
| a constructor, or anything else that would prevent static initialization. |
| All <code class="computeroutput"><a class="link" href="../boost/proto/expr.html" title="Struct template expr">proto::expr<></a></code> objects are initialized |
| using <span class="emphasis"><em>aggregate initialization</em></span>, with curly braces. In |
| our example, <code class="computeroutput"><span class="identifier">_1</span></code> is initialized |
| with the initializer <code class="computeroutput"><span class="special">{{}}</span></code>. The |
| outer braces are the initializer for the <code class="computeroutput"><a class="link" href="../boost/proto/expr.html" title="Struct template expr">proto::expr<></a></code> |
| struct, and the inner braces are for the member <code class="computeroutput"><span class="identifier">_1</span><span class="special">.</span><span class="identifier">child0</span></code> |
| which is of type <code class="computeroutput"><span class="identifier">placeholder</span><span class="special"><</span><span class="number">0</span><span class="special">></span></code>. |
| Note that we use braces to initialize <code class="computeroutput"><span class="identifier">_1</span><span class="special">.</span><span class="identifier">child0</span></code> |
| because <code class="computeroutput"><span class="identifier">placeholder</span><span class="special"><</span><span class="number">0</span><span class="special">></span></code> is also |
| an aggregate. |
| </p> |
| <a name="boost_proto.users_guide.intermediate_form.building_expression_trees"></a><h5> |
| <a name="boost_proto.users_guide.intermediate_form.building_expression_trees-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.building_expression_trees">Building |
| Expression Trees</a> |
| </h5> |
| <p> |
| The <code class="computeroutput"><span class="identifier">_1</span></code> node is an instantiation |
| of <code class="computeroutput"><a class="link" href="../boost/proto/expr.html" title="Struct template expr">proto::expr<></a></code>, and expressions containing |
| <code class="computeroutput"><span class="identifier">_1</span></code> are also instantiations |
| of <code class="computeroutput"><a class="link" href="../boost/proto/expr.html" title="Struct template expr">proto::expr<></a></code>. To use Proto effectively, |
| you won't have to bother yourself with the actual types that Proto generates. |
| These are details, but you're likely to encounter these types in compiler |
| error messages, so it's helpful to be familiar with them. The types look |
| like this: |
| </p> |
| <pre class="programlisting"><span class="comment">// The type of the expression -_1</span> |
| <span class="keyword">typedef</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">expr</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">negate</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">list1</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">expr</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">term</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="number">0</span><span class="special">></span> <span class="special">></span> |
| <span class="special">,</span> <span class="number">0</span> |
| <span class="special">></span> <span class="keyword">const</span> <span class="special">&</span> |
| <span class="special">></span> |
| <span class="special">,</span> <span class="number">1</span> |
| <span class="special">></span> |
| <span class="identifier">negate_placeholder_type</span><span class="special">;</span> |
| |
| <span class="identifier">negate_placeholder_type</span> <span class="identifier">x</span> <span class="special">=</span> <span class="special">-</span><span class="identifier">_1</span><span class="special">;</span> |
| |
| <span class="comment">// The type of the expression _1 + 42</span> |
| <span class="keyword">typedef</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">expr</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">plus</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">list2</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">expr</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">term</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="number">0</span><span class="special">></span> <span class="special">></span> |
| <span class="special">,</span> <span class="number">0</span> |
| <span class="special">></span> <span class="keyword">const</span> <span class="special">&</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">expr</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">term</span><span class="special"><</span> <span class="keyword">int</span> <span class="keyword">const</span> <span class="special">&</span> <span class="special">></span> |
| <span class="special">,</span> <span class="number">0</span> |
| <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">,</span> <span class="number">2</span> |
| <span class="special">></span> |
| <span class="identifier">placeholder_plus_int_type</span><span class="special">;</span> |
| |
| <span class="identifier">placeholder_plus_int_type</span> <span class="identifier">y</span> <span class="special">=</span> <span class="identifier">_1</span> <span class="special">+</span> <span class="number">42</span><span class="special">;</span> |
| </pre> |
| <p> |
| There are a few things to note about these types: |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"> |
| <li class="listitem"> |
| Terminals have arity zero, unary expressions have arity one and binary |
| expressions have arity two. |
| </li> |
| <li class="listitem"> |
| When one Proto expression is made a child node of another Proto expression, |
| it is held by reference, <span class="emphasis"><em>even if it is a temporary object</em></span>. |
| This last point becomes important later. |
| </li> |
| <li class="listitem"> |
| Non-Proto expressions, such as the integer literal, are turned into Proto |
| expressions by wrapping them in new <code class="computeroutput"><span class="identifier">expr</span><span class="special"><></span></code> terminal objects. These new wrappers |
| are not themselves held by reference, but the object wrapped <span class="emphasis"><em>is</em></span>. |
| Notice that the type of the Protofied <code class="computeroutput"><span class="number">42</span></code> |
| literal is <code class="computeroutput"><span class="keyword">int</span> <span class="keyword">const</span> |
| <span class="special">&</span></code> -- held by reference. |
| </li> |
| </ul></div> |
| <p> |
| The types make it clear: everything in a Proto expression tree is held by |
| reference. That means that building an expression tree is exceptionally cheap. |
| It involves no copying at all. |
| </p> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| An astute reader will notice that the object <code class="computeroutput"><span class="identifier">y</span></code> |
| defined above will be left holding a dangling reference to a temporary |
| int. In the sorts of high-performance applications Proto addresses, it |
| is typical to build and evaluate an expression tree before any temporary |
| objects go out of scope, so this dangling reference situation often doesn't |
| arise, but it is certainly something to be aware of. Proto provides utilities |
| for deep-copying expression trees so they can be passed around as value |
| types without concern for dangling references. |
| </p></td></tr> |
| </table></div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.intermediate_form.left_right_child"></a><a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.left_right_child" title="Accessing Parts of an Expression">Accessing |
| Parts of an Expression</a> |
| </h4></div></div></div> |
| <p> |
| After assembling an expression into a tree, you'll naturally want to be |
| able to do the reverse, and access a node's children. You may even want |
| to be able to iterate over the children with algorithms from the Boost.Fusion |
| library. This section shows how. |
| </p> |
| <a name="boost_proto.users_guide.intermediate_form.left_right_child.getting_expression_tags_and_arities"></a><h6> |
| <a name="boost_proto.users_guide.intermediate_form.left_right_child.getting_expression_tags_and_arities-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.left_right_child.getting_expression_tags_and_arities">Getting |
| Expression Tags and Arities</a> |
| </h6> |
| <p> |
| Every node in an expression tree has both a <span class="emphasis"><em>tag</em></span> type |
| that describes the node, and an <span class="emphasis"><em>arity</em></span> corresponding |
| to the number of child nodes it has. You can use the <code class="computeroutput"><a class="link" href="../boost/proto/tag_of.html" title="Struct template tag_of">proto::tag_of<></a></code> |
| and <code class="computeroutput"><a class="link" href="../boost/proto/arity_of.html" title="Struct template arity_of">proto::arity_of<></a></code> metafunctions to fetch |
| them. Consider the following: |
| </p> |
| <pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">void</span> <span class="identifier">check_plus_node</span><span class="special">(</span><span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&)</span> |
| <span class="special">{</span> |
| <span class="comment">// Assert that the tag type is proto::tag::plus</span> |
| <span class="identifier">BOOST_STATIC_ASSERT</span><span class="special">((</span> |
| <span class="identifier">boost</span><span class="special">::</span><span class="identifier">is_same</span><span class="special"><</span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag_of</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">plus</span> |
| <span class="special">>::</span><span class="identifier">value</span> |
| <span class="special">));</span> |
| |
| <span class="comment">// Assert that the arity is 2</span> |
| <span class="identifier">BOOST_STATIC_ASSERT</span><span class="special">(</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">arity_of</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="identifier">value</span> <span class="special">==</span> <span class="number">2</span> <span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="comment">// Create a binary plus node and use check_plus_node()</span> |
| <span class="comment">// to verify its tag type and arity:</span> |
| <span class="identifier">check_plus_node</span><span class="special">(</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">lit</span><span class="special">(</span><span class="number">1</span><span class="special">)</span> <span class="special">+</span> <span class="number">2</span> <span class="special">);</span> |
| </pre> |
| <p> |
| For a given type <code class="computeroutput"><span class="identifier">Expr</span></code>, |
| you could access the tag and arity directly as <code class="computeroutput"><span class="identifier">Expr</span><span class="special">::</span><span class="identifier">proto_tag</span></code> |
| and <code class="computeroutput"><span class="identifier">Expr</span><span class="special">::</span><span class="identifier">proto_arity</span></code>, where <code class="computeroutput"><span class="identifier">Expr</span><span class="special">::</span><span class="identifier">proto_arity</span></code> |
| is an MPL Integral Constant. |
| </p> |
| <a name="boost_proto.users_guide.intermediate_form.left_right_child.getting_terminal_values"></a><h6> |
| <a name="boost_proto.users_guide.intermediate_form.left_right_child.getting_terminal_values-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.left_right_child.getting_terminal_values">Getting |
| Terminal Values</a> |
| </h6> |
| <p> |
| There is no simpler expression than a terminal, and no more basic operation |
| than extracting its value. As we've already seen, that is what <code class="computeroutput"><a class="link" href="../boost/proto/value_id1386962.html" title="Function value">proto::value()</a></code> is for. |
| </p> |
| <pre class="programlisting"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span> <span class="special">>::</span><span class="identifier">type</span> <span class="identifier">cout_</span> <span class="special">=</span> <span class="special">{</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">};</span> |
| |
| <span class="comment">// Get the value of the cout_ terminal:</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span> <span class="identifier">sout</span> <span class="special">=</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">value</span><span class="special">(</span> <span class="identifier">cout_</span> <span class="special">);</span> |
| |
| <span class="comment">// Assert that we got back what we put in:</span> |
| <span class="identifier">assert</span><span class="special">(</span> <span class="special">&</span><span class="identifier">sout</span> <span class="special">==</span> <span class="special">&</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">);</span> |
| </pre> |
| <p> |
| To compute the return type of the <code class="computeroutput"><a class="link" href="../boost/proto/value_id1386962.html" title="Function value">proto::value()</a></code> |
| function, you can use <code class="computeroutput"><a class="link" href="../boost/proto/result_of/value.html" title="Struct template value">proto::result_of::value<></a></code>. |
| When the parameter to <code class="computeroutput"><a class="link" href="../boost/proto/result_of/value.html" title="Struct template value">proto::result_of::value<></a></code> |
| is a non-reference type, the result type of the metafunction is the type |
| of the value as suitable for storage by value; that is, top-level reference |
| and qualifiers are stripped from it. But when instantiated with a reference |
| type, the result type has a reference <span class="emphasis"><em>added</em></span> to it, |
| yielding a type suitable for storage by reference. If you want to know |
| the actual type of the terminal's value including whether it is stored |
| by value or reference, you can use <code class="computeroutput"><span class="identifier">fusion</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">value_at</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="number">0</span><span class="special">>::</span><span class="identifier">type</span></code>. |
| </p> |
| <p> |
| The following table summarizes the above paragraph. |
| </p> |
| <div class="table"> |
| <a name="id2306311"></a><p class="title"><b>Table 16.3. Accessing Value Types</b></p> |
| <div class="table-contents"><table class="table" summary="Accessing Value Types"> |
| <colgroup> |
| <col> |
| <col> |
| <col> |
| </colgroup> |
| <thead><tr> |
| <th> |
| <p> |
| Metafunction Invocation |
| </p> |
| </th> |
| <th> |
| <p> |
| When the Value Type Is ... |
| </p> |
| </th> |
| <th> |
| <p> |
| The Result Is ... |
| </p> |
| </th> |
| </tr></thead> |
| <tbody> |
| <tr> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">value</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="identifier">type</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">T</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">remove_const</span><span class="special"><</span> |
| <span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">remove_reference</span><span class="special"><</span><span class="identifier">T</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">>::</span><span class="identifier">type</span> <sup>[<a name="id2306502" href="#ftn.id2306502" class="footnote">a</a>]</sup></pre> |
| <p> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">value</span><span class="special"><</span><span class="identifier">Expr</span> <span class="special">&>::</span><span class="identifier">type</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">T</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">add_reference</span><span class="special"><</span><span class="identifier">T</span><span class="special">>::</span><span class="identifier">type</span></pre> |
| <p> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">value</span><span class="special"><</span><span class="identifier">Expr</span> <span class="keyword">const</span> |
| <span class="special">&>::</span><span class="identifier">type</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">T</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">add_reference</span><span class="special"><</span> |
| <span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">add_const</span><span class="special"><</span><span class="identifier">T</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">>::</span><span class="identifier">type</span></pre> |
| <p> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">fusion</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">value_at</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> |
| <span class="number">0</span><span class="special">>::</span><span class="identifier">type</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">T</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">T</span></code> |
| </p> |
| </td> |
| </tr> |
| </tbody> |
| <tbody class="footnotes"><tr><td colspan="3"><div class="footnote"><p><sup>[<a id="ftn.id2306502" href="#id2306502" class="para">a</a>] </sup>If <code class="computeroutput"><span class="identifier">T</span></code> is a reference-to-function type, then the result type is simply <code class="computeroutput"><span class="identifier">T</span></code>.</p></div></td></tr></tbody> |
| </table></div> |
| </div> |
| <br class="table-break"><a name="boost_proto.users_guide.intermediate_form.left_right_child.getting_child_expressions"></a><h6> |
| <a name="boost_proto.users_guide.intermediate_form.left_right_child.getting_child_expressions-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.left_right_child.getting_child_expressions">Getting |
| Child Expressions</a> |
| </h6> |
| <p> |
| Each non-terminal node in an expression tree corresponds to an operator |
| in an expression, and the children correspond to the operands, or arguments |
| of the operator. To access them, you can use the <code class="computeroutput"><a class="link" href="../boost/proto/child_c_id1386801.html" title="Function child_c">proto::child_c()</a></code> |
| function template, as demonstrated below: |
| </p> |
| <pre class="programlisting"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">>::</span><span class="identifier">type</span> <span class="identifier">i</span> <span class="special">=</span> <span class="special">{</span><span class="number">42</span><span class="special">};</span> |
| |
| <span class="comment">// Get the 0-th operand of an addition operation:</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">>::</span><span class="identifier">type</span> <span class="special">&</span><span class="identifier">ri</span> <span class="special">=</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="number">0</span><span class="special">>(</span> <span class="identifier">i</span> <span class="special">+</span> <span class="number">2</span> <span class="special">);</span> |
| |
| <span class="comment">// Assert that we got back what we put in:</span> |
| <span class="identifier">assert</span><span class="special">(</span> <span class="special">&</span><span class="identifier">i</span> <span class="special">==</span> <span class="special">&</span><span class="identifier">ri</span> <span class="special">);</span> |
| </pre> |
| <p> |
| You can use the <code class="computeroutput"><a class="link" href="../boost/proto/result_of/child_c.html" title="Struct template child_c">proto::result_of::child_c<></a></code> |
| metafunction to get the type of the Nth child of an expression node. Usually |
| you don't care to know whether a child is stored by value or by reference, |
| so when you ask for the type of the Nth child of an expression <code class="computeroutput"><span class="identifier">Expr</span></code> (where <code class="computeroutput"><span class="identifier">Expr</span></code> |
| is not a reference type), you get the child's type after references and |
| cv-qualifiers have been stripped from it. |
| </p> |
| <pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">void</span> <span class="identifier">test_result_of_child_c</span><span class="special">(</span><span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="number">0</span><span class="special">>::</span><span class="identifier">type</span> <span class="identifier">type</span><span class="special">;</span> |
| |
| <span class="comment">// Since Expr is not a reference type,</span> |
| <span class="comment">// result_of::child_c<Expr, 0>::type is a</span> |
| <span class="comment">// non-cv qualified, non-reference type:</span> |
| <span class="identifier">BOOST_MPL_ASSERT</span><span class="special">((</span> |
| <span class="identifier">boost</span><span class="special">::</span><span class="identifier">is_same</span><span class="special"><</span> <span class="identifier">type</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">>::</span><span class="identifier">type</span> <span class="special">></span> |
| <span class="special">));</span> |
| <span class="special">}</span> |
| |
| <span class="comment">// ...</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">>::</span><span class="identifier">type</span> <span class="identifier">i</span> <span class="special">=</span> <span class="special">{</span><span class="number">42</span><span class="special">};</span> |
| <span class="identifier">test_result_of_child_c</span><span class="special">(</span> <span class="identifier">i</span> <span class="special">+</span> <span class="number">2</span> <span class="special">);</span> |
| </pre> |
| <p> |
| However, if you ask for the type of the Nth child of <code class="computeroutput"><span class="identifier">Expr</span> |
| <span class="special">&</span></code> or <code class="computeroutput"><span class="identifier">Expr</span> |
| <span class="keyword">const</span> <span class="special">&</span></code> |
| (note the reference), the result type will be a reference, regardless of |
| whether the child is actually stored by reference or not. If you need to |
| know exactly how the child is stored in the node, whether by reference |
| or by value, you can use <code class="computeroutput"><span class="identifier">fusion</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">value_at</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">N</span><span class="special">>::</span><span class="identifier">type</span></code>. The following table summarizes |
| the behavior of the <code class="computeroutput"><a class="link" href="../boost/proto/result_of/child_c.html" title="Struct template child_c">proto::result_of::child_c<></a></code> |
| metafunction. |
| </p> |
| <div class="table"> |
| <a name="id2307934"></a><p class="title"><b>Table 16.4. Accessing Child Types</b></p> |
| <div class="table-contents"><table class="table" summary="Accessing Child Types"> |
| <colgroup> |
| <col> |
| <col> |
| <col> |
| </colgroup> |
| <thead><tr> |
| <th> |
| <p> |
| Metafunction Invocation |
| </p> |
| </th> |
| <th> |
| <p> |
| When the Child Is ... |
| </p> |
| </th> |
| <th> |
| <p> |
| The Result Is ... |
| </p> |
| </th> |
| </tr></thead> |
| <tbody> |
| <tr> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> |
| <span class="identifier">N</span><span class="special">>::</span><span class="identifier">type</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">T</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">remove_const</span><span class="special"><</span> |
| <span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">remove_reference</span><span class="special"><</span><span class="identifier">T</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">>::</span><span class="identifier">type</span></pre> |
| <p> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="identifier">Expr</span> <span class="special">&,</span> |
| <span class="identifier">N</span><span class="special">>::</span><span class="identifier">type</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">T</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">add_reference</span><span class="special"><</span><span class="identifier">T</span><span class="special">>::</span><span class="identifier">type</span></pre> |
| <p> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="identifier">Expr</span> <span class="keyword">const</span> |
| <span class="special">&,</span> <span class="identifier">N</span><span class="special">>::</span><span class="identifier">type</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">T</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">add_reference</span><span class="special"><</span> |
| <span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">add_const</span><span class="special"><</span><span class="identifier">T</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">>::</span><span class="identifier">type</span></pre> |
| <p> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">fusion</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">value_at</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> |
| <span class="identifier">N</span><span class="special">>::</span><span class="identifier">type</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">T</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">T</span></code> |
| </p> |
| </td> |
| </tr> |
| </tbody> |
| </table></div> |
| </div> |
| <br class="table-break"><a name="boost_proto.users_guide.intermediate_form.left_right_child.common_shortcuts"></a><h6> |
| <a name="boost_proto.users_guide.intermediate_form.left_right_child.common_shortcuts-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.left_right_child.common_shortcuts">Common |
| Shortcuts</a> |
| </h6> |
| <p> |
| Most operators in C++ are unary or binary, so accessing the only operand, |
| or the left and right operands, are very common operations. For this reason, |
| Proto provides the <code class="computeroutput"><a class="link" href="../boost/proto/child_id1386559.html" title="Function child">proto::child()</a></code>, |
| <code class="computeroutput"><a class="link" href="../boost/proto/left_id1387069.html" title="Function left">proto::left()</a></code>, and <code class="computeroutput"><a class="link" href="../boost/proto/right_id1387192.html" title="Function right">proto::right()</a></code> |
| functions. <code class="computeroutput"><a class="link" href="../boost/proto/child_id1386559.html" title="Function child">proto::child()</a></code> and <code class="computeroutput"><a class="link" href="../boost/proto/left_id1387069.html" title="Function left">proto::left()</a></code> |
| are synonymous with <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="number">0</span><span class="special">>()</span></code>, |
| and <code class="computeroutput"><a class="link" href="../boost/proto/right_id1387192.html" title="Function right">proto::right()</a></code> is synonymous with <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="number">1</span><span class="special">>()</span></code>. |
| </p> |
| <p> |
| There are also <code class="computeroutput"><a class="link" href="../boost/proto/result_of/child.html" title="Struct template child">proto::result_of::child<></a></code>, |
| <code class="computeroutput"><a class="link" href="../boost/proto/result_of/left.html" title="Struct template left">proto::result_of::left<></a></code>, and <code class="computeroutput"><a class="link" href="../boost/proto/result_of/right.html" title="Struct template right">proto::result_of::right<></a></code> |
| metafunctions that merely forward to their <code class="computeroutput"><a class="link" href="../boost/proto/result_of/child_c.html" title="Struct template child_c">proto::result_of::child_c<></a></code> |
| counterparts. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.intermediate_form.deep_copying_expressions"></a><a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.deep_copying_expressions" title="Deep-copying Expressions">Deep-copying |
| Expressions</a> |
| </h4></div></div></div> |
| <p> |
| When you build an expression template with Proto, all the intermediate |
| child nodes are held <span class="emphasis"><em>by reference</em></span>. The avoids needless |
| copies, which is crucial if you want your DSEL to perform well at runtime. |
| Naturally, there is a danger if the temporary objects go out of scope before |
| you try to evaluate your expression template. This is especially a problem |
| in C++0x with the new <code class="computeroutput"><span class="identifier">decltype</span></code> |
| and <code class="computeroutput"><span class="keyword">auto</span></code> keywords. Consider: |
| </p> |
| <pre class="programlisting"><span class="comment">// OOPS: "ex" is left holding dangling references</span> |
| <span class="keyword">auto</span> <span class="identifier">ex</span> <span class="special">=</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">lit</span><span class="special">(</span><span class="number">1</span><span class="special">)</span> <span class="special">+</span> <span class="number">2</span><span class="special">;</span> |
| </pre> |
| <p> |
| The problem can happen in today's C++ also if you use <code class="computeroutput"><span class="identifier">BOOST_TYPEOF</span><span class="special">()</span></code> or <code class="computeroutput"><span class="identifier">BOOST_AUTO</span><span class="special">()</span></code>, or if you try to pass an expression |
| template outside the scope of its constituents. |
| </p> |
| <p> |
| In these cases, you want to deep-copy your expression template so that |
| all intermediate nodes and the terminals are held <span class="emphasis"><em>by value</em></span>. |
| That way, you can safely assign the expression template to a local variable |
| or return it from a function without worrying about dangling references. |
| You can do this with <code class="computeroutput"><a class="link" href="../boost/proto/deep_copy_id1352831.html" title="Function template deep_copy">proto::deep_copy()</a></code> |
| as fo llows: |
| </p> |
| <pre class="programlisting"><span class="comment">// OK, "ex" has no dangling references</span> |
| <span class="keyword">auto</span> <span class="identifier">ex</span> <span class="special">=</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">deep_copy</span><span class="special">(</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">lit</span><span class="special">(</span><span class="number">1</span><span class="special">)</span> <span class="special">+</span> <span class="number">2</span> <span class="special">);</span> |
| </pre> |
| <p> |
| If you are using <a href="../../../libs/typeof/index.html" target="_top">Boost.Typeof</a>, |
| it would look like this: |
| </p> |
| <pre class="programlisting"><span class="comment">// OK, use BOOST_AUTO() and proto::deep_copy() to</span> |
| <span class="comment">// store an expression template in a local variable </span> |
| <span class="identifier">BOOST_AUTO</span><span class="special">(</span> <span class="identifier">ex</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">deep_copy</span><span class="special">(</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">lit</span><span class="special">(</span><span class="number">1</span><span class="special">)</span> <span class="special">+</span> <span class="number">2</span> <span class="special">)</span> <span class="special">);</span> |
| </pre> |
| <p> |
| For the above code to work, you must include the <code class="computeroutput"><a class="link" href="reference.html#header.boost.proto.proto_typeof_hpp" title="Header <boost/proto/proto_typeof.hpp>">boost/proto/proto_typeof.hpp</a></code> |
| header, which also defines the <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_AUTO.html" title="Macro BOOST_PROTO_AUTO">BOOST_PROTO_AUTO</a></code>()</code> |
| macro which automatically deep-copies its argument. With <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_AUTO.html" title="Macro BOOST_PROTO_AUTO">BOOST_PROTO_AUTO</a></code>()</code>, the above |
| code can be writen as: |
| </p> |
| <pre class="programlisting"><span class="comment">// OK, BOOST_PROTO_AUTO() automatically deep-copies</span> |
| <span class="comment">// its argument: </span> |
| <span class="identifier">BOOST_PROTO_AUTO</span><span class="special">(</span> <span class="identifier">ex</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">lit</span><span class="special">(</span><span class="number">1</span><span class="special">)</span> <span class="special">+</span> <span class="number">2</span> <span class="special">);</span> |
| </pre> |
| <p> |
| When deep-copying an expression tree, all intermediate nodes and all terminals |
| are stored by value. The only exception is terminals that are function |
| references, which are left alone. |
| </p> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| <code class="computeroutput"><a class="link" href="../boost/proto/deep_copy_id1352831.html" title="Function template deep_copy">proto::deep_copy()</a></code> makes no exception for |
| arrays, which it stores by value. That can potentially cause a large |
| amount of data to be copied. |
| </p></td></tr> |
| </table></div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.intermediate_form.debugging_expressions"></a><a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.debugging_expressions" title="Debugging Expressions">Debugging |
| Expressions</a> |
| </h4></div></div></div> |
| <p> |
| Proto provides a utility for pretty-printing expression trees that comes |
| in very handy when you're trying to debug your DSEL. It's called <code class="computeroutput"><a class="link" href="../boost/proto/display_expr_id1351948.html" title="Function display_expr">proto::display_expr()</a></code>, and you pass it the expression |
| to print and optionally, an <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span></code> |
| to which to send the output. Consider: |
| </p> |
| <pre class="programlisting"><span class="comment">// Use display_expr() to pretty-print an expression tree</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">display_expr</span><span class="special">(</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">lit</span><span class="special">(</span><span class="string">"hello"</span><span class="special">)</span> <span class="special">+</span> <span class="number">42</span> |
| <span class="special">);</span> |
| </pre> |
| <p> |
| The above code writes this to <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span></code>: |
| </p> |
| <pre class="programlisting">plus( |
| terminal(hello) |
| , terminal(42) |
| )</pre> |
| <p> |
| In order to call <code class="computeroutput"><a class="link" href="../boost/proto/display_expr_id1351948.html" title="Function display_expr">proto::display_expr()</a></code>, |
| all the terminals in the expression must be Streamable (that is, they can |
| be written to a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span></code>). In addition, the tag types |
| must all be Streamable as well. Here is an example that includes a custom |
| terminal type and a custom tag: |
| </p> |
| <pre class="programlisting"><span class="comment">// A custom tag type that is Streamable</span> |
| <span class="keyword">struct</span> <span class="identifier">MyTag</span> |
| <span class="special">{</span> |
| <span class="keyword">friend</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="keyword">operator</span><span class="special"><<(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="identifier">s</span><span class="special">,</span> <span class="identifier">MyTag</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">s</span> <span class="special"><<</span> <span class="string">"MyTag"</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Some other Streamable type</span> |
| <span class="keyword">struct</span> <span class="identifier">MyTerminal</span> |
| <span class="special">{</span> |
| <span class="keyword">friend</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="keyword">operator</span><span class="special"><<(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="identifier">s</span><span class="special">,</span> <span class="identifier">MyTerminal</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">s</span> <span class="special"><<</span> <span class="string">"MyTerminal"</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="comment">// Display an expression tree that contains a custom</span> |
| <span class="comment">// tag and a user-defined type in a terminal</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">display_expr</span><span class="special">(</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">make_expr</span><span class="special"><</span><span class="identifier">MyTag</span><span class="special">>(</span><span class="identifier">MyTerminal</span><span class="special">())</span> <span class="special">+</span> <span class="number">42</span> |
| <span class="special">);</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| The above code prints the following: |
| </p> |
| <pre class="programlisting">plus( |
| MyTag( |
| terminal(MyTerminal) |
| ) |
| , terminal(42) |
| )</pre> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.intermediate_form.tags_and_metafunctions"></a><a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.tags_and_metafunctions" title="Operator Tags and Metafunctions">Operator |
| Tags and Metafunctions</a> |
| </h4></div></div></div> |
| <p> |
| The following table lists the overloadable C++ operators, the Proto tag |
| types for each, and the name of the metafunctions for generating the corresponding |
| Proto expression types. And as we'll see later, the metafunctions are also |
| usable as grammars for matching such nodes, as well as pass-through transforms. |
| </p> |
| <div class="table"> |
| <a name="id2309917"></a><p class="title"><b>Table 16.5. Operators, Tags and Metafunctions</b></p> |
| <div class="table-contents"><table class="table" summary="Operators, Tags and Metafunctions"> |
| <colgroup> |
| <col> |
| <col> |
| <col> |
| </colgroup> |
| <thead><tr> |
| <th> |
| <p> |
| Operator |
| </p> |
| </th> |
| <th> |
| <p> |
| Proto Tag |
| </p> |
| </th> |
| <th> |
| <p> |
| Proto Metafunction |
| </p> |
| </th> |
| </tr></thead> |
| <tbody> |
| <tr> |
| <td> |
| <p> |
| unary <code class="computeroutput"><span class="special">+</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">unary_plus</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">unary_plus</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| unary <code class="computeroutput"><span class="special">-</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">negate</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">negate</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| unary <code class="computeroutput"><span class="special">*</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">dereference</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">dereference</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| unary <code class="computeroutput"><span class="special">~</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">complement</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">complement</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| unary <code class="computeroutput"><span class="special">&</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">address_of</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">address_of</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| unary <code class="computeroutput"><span class="special">!</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">logical_not</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">logical_not</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| unary prefix <code class="computeroutput"><span class="special">++</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">pre_inc</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">pre_inc</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| unary prefix <code class="computeroutput"><span class="special">--</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">pre_dec</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">pre_dec</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| unary postfix <code class="computeroutput"><span class="special">++</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">post_inc</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">post_inc</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| unary postfix <code class="computeroutput"><span class="special">--</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">post_dec</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">post_dec</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special"><<</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">shift_left</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_left</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">>></span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">shift_right</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_right</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">*</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">multiplies</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">multiplies</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">/</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">divides</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">divides</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">%</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">modulus</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">modulus</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">+</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">plus</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">-</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">minus</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">minus</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special"><</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">less</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">less</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">></span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">greater</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">greater</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special"><=</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">less_equal</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">less_equal</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">>=</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">greater_equal</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">greater_equal</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">==</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">equal_to</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">equal_to</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">!=</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">not_equal_to</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">not_equal_to</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">||</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">logical_or</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">logical_or</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">&&</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">logical_and</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">logical_and</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">&</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">bitwise_and</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">bitwise_and</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">|</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">bitwise_or</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">bitwise_or</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">^</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">bitwise_xor</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">bitwise_xor</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">,</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">comma</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">comma</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">->*</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">mem_ptr</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">mem_ptr</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">=</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">assign</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">assign</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special"><<=</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">shift_left_assign</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_left_assign</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">>>=</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">shift_right_assign</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_right_assign</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">*=</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">multiplies_assign</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">multiplies_assign</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">/=</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">divides_assign</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">divides_assign</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">%=</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">modulus_assign</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">modulus_assign</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">+=</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">plus_assign</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus_assign</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">-=</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">minus_assign</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">minus_assign</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">&=</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">bitwise_and_assign</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">bitwise_and_assign</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">|=</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">bitwise_or_assign</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">bitwise_or_assign</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary <code class="computeroutput"><span class="special">^=</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">bitwise_xor_assign</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">bitwise_xor_assign</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| binary subscript |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">subscript</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">subscript</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| ternary <code class="computeroutput"><span class="special">?:</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">if_else_</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">if_else_</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| n-ary function call |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">function</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">function</span><span class="special"><></span></code> |
| </p> |
| </td> |
| </tr> |
| </tbody> |
| </table></div> |
| </div> |
| <br class="table-break"> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.intermediate_form.expressions_as_fusion_sequences"></a><a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.expressions_as_fusion_sequences" title="Expressions as Fusion Sequences">Expressions |
| as Fusion Sequences</a> |
| </h4></div></div></div> |
| <p> |
| Boost.Fusion is a library of iterators, algorithms, containers and adaptors |
| for manipulating heterogeneous sequences. In essence, a Proto expression |
| is just a heterogeneous sequence of its child expressions, and so Proto |
| expressions are valid Fusion random-access sequences. That means you can |
| apply Fusion algorithms to them, transform them, apply Fusion filters and |
| views to them, and access their elements using <code class="computeroutput"><span class="identifier">fusion</span><span class="special">::</span><span class="identifier">at</span><span class="special">()</span></code>. The things Fusion can do to heterogeneous |
| sequences are beyond the scope of this users' guide, but below is a simple |
| example. It takes a lazy function invocation like <code class="computeroutput"><span class="identifier">fun</span><span class="special">(</span><span class="number">1</span><span class="special">,</span><span class="number">2</span><span class="special">,</span><span class="number">3</span><span class="special">,</span><span class="number">4</span><span class="special">)</span></code> |
| and uses Fusion to print the function arguments in order. |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">display</span> |
| <span class="special">{</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">></span> |
| <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">T</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">t</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">t</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">fun_t</span> <span class="special">{};</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">fun_t</span><span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">fun</span> <span class="special">=</span> <span class="special">{{}};</span> |
| |
| <span class="comment">// ...</span> |
| <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">for_each</span><span class="special">(</span> |
| <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">transform</span><span class="special">(</span> |
| <span class="comment">// pop_front() removes the "fun" child</span> |
| <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">pop_front</span><span class="special">(</span><span class="identifier">fun</span><span class="special">(</span><span class="number">1</span><span class="special">,</span><span class="number">2</span><span class="special">,</span><span class="number">3</span><span class="special">,</span><span class="number">4</span><span class="special">))</span> |
| <span class="comment">// Extract the ints from the terminal nodes</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">functional</span><span class="special">::</span><span class="identifier">value</span><span class="special">()</span> |
| <span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">display</span><span class="special">()</span> |
| <span class="special">);</span> |
| </pre> |
| <p> |
| Recall from the Introduction that types in the <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">functional</span></code> |
| namespace define function objects that correspond to Proto's free functions. |
| So <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">functional</span><span class="special">::</span><span class="identifier">value</span><span class="special">()</span></code> |
| creates a function object that is equivalent to the <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">value</span><span class="special">()</span></code> function. The above invocation of <code class="computeroutput"><span class="identifier">fusion</span><span class="special">::</span><span class="identifier">for_each</span><span class="special">()</span></code> |
| displays the following: |
| </p> |
| <pre class="programlisting">1 |
| 2 |
| 3 |
| 4 |
| </pre> |
| <p> |
| Terminals are also valid Fusion sequences. They contain exactly one element: |
| their value. |
| </p> |
| <a name="boost_proto.users_guide.intermediate_form.expressions_as_fusion_sequences.flattening_proto_expression_tress"></a><h6> |
| <a name="boost_proto.users_guide.intermediate_form.expressions_as_fusion_sequences.flattening_proto_expression_tress-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.expressions_as_fusion_sequences.flattening_proto_expression_tress">Flattening |
| Proto Expression Tress</a> |
| </h6> |
| <p> |
| Imagine a slight variation of the above example where, instead of iterating |
| over the arguments of a lazy function invocation, we would like to iterate |
| over the terminals in an addition expression: |
| </p> |
| <pre class="programlisting"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">_1</span> <span class="special">=</span> <span class="special">{</span><span class="number">1</span><span class="special">};</span> |
| |
| <span class="comment">// ERROR: this doesn't work! Why?</span> |
| <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">for_each</span><span class="special">(</span> |
| <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">transform</span><span class="special">(</span> |
| <span class="identifier">_1</span> <span class="special">+</span> <span class="number">2</span> <span class="special">+</span> <span class="number">3</span> <span class="special">+</span> <span class="number">4</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">functional</span><span class="special">::</span><span class="identifier">value</span><span class="special">()</span> |
| <span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">display</span><span class="special">()</span> |
| <span class="special">);</span> |
| </pre> |
| <p> |
| The reason this doesn't work is because the expression <code class="computeroutput"><span class="identifier">_1</span> |
| <span class="special">+</span> <span class="number">2</span> <span class="special">+</span> <span class="number">3</span> <span class="special">+</span> |
| <span class="number">4</span></code> does not describe a flat sequence |
| of terminals --- it describes a binary tree. We can treat it as a flat |
| sequence of terminals, however, using Proto's <code class="computeroutput"><a class="link" href="../boost/proto/flatten_id1359907.html" title="Function flatten">proto::flatten()</a></code> |
| function. <code class="computeroutput"><a class="link" href="../boost/proto/flatten_id1359907.html" title="Function flatten">proto::flatten()</a></code> returns a view which makes |
| a tree appear as a flat Fusion sequence. If the top-most node has a tag |
| type <code class="computeroutput"><span class="identifier">T</span></code>, then the elements |
| of the flattened sequence are the child nodes that do <span class="emphasis"><em>not</em></span> |
| have tag type <code class="computeroutput"><span class="identifier">T</span></code>. This process |
| is evaluated recursively. So the above can correctly be written as: |
| </p> |
| <pre class="programlisting"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">_1</span> <span class="special">=</span> <span class="special">{</span><span class="number">1</span><span class="special">};</span> |
| |
| <span class="comment">// OK, iterate over a flattened view</span> |
| <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">for_each</span><span class="special">(</span> |
| <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">transform</span><span class="special">(</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">flatten</span><span class="special">(</span><span class="identifier">_1</span> <span class="special">+</span> <span class="number">2</span> <span class="special">+</span> <span class="number">3</span> <span class="special">+</span> <span class="number">4</span><span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">functional</span><span class="special">::</span><span class="identifier">value</span><span class="special">()</span> |
| <span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">display</span><span class="special">()</span> |
| <span class="special">);</span> |
| </pre> |
| <p> |
| The above invocation of <code class="computeroutput"><span class="identifier">fusion</span><span class="special">::</span><span class="identifier">for_each</span><span class="special">()</span></code> displays the following: |
| </p> |
| <pre class="programlisting">1 |
| 2 |
| 3 |
| 4 |
| </pre> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.intermediate_form.expression_introspection"></a><a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.expression_introspection" title="Expression Introspection: Defining a Grammar">Expression |
| Introspection: Defining a Grammar</a> |
| </h4></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.intermediate_form.expression_introspection.patterns">Finding |
| Patterns in Expressions</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.intermediate_form.expression_introspection.fuzzy_and_exact_matches_of_terminals">Fuzzy |
| and Exact Matches of Terminals</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.intermediate_form.expression_introspection.if_and_not"><code class="literal">if_<></code>, |
| <code class="literal">and_<></code>, and <code class="literal">not_<></code></a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.intermediate_form.expression_introspection.switch">Improving |
| Compile Times With <code class="literal">switch_<></code></a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.intermediate_form.expression_introspection.matching_vararg_expressions">Matching |
| Vararg Expressions</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.intermediate_form.expression_introspection.defining_dsel_grammars">Defining |
| DSEL Grammars</a></span></dt> |
| </dl></div> |
| <p> |
| Expression trees can have a very rich and complicated structure. Often, |
| you need to know some things about an expression's structure before you |
| can process it. This section describes the tools Proto provides for peering |
| inside an expression tree and discovering its structure. And as you'll |
| see in later sections, all the really interesting things you can do with |
| Proto begin right here. |
| </p> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.intermediate_form.expression_introspection.patterns"></a><a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.expression_introspection.patterns" title="Finding Patterns in Expressions">Finding |
| Patterns in Expressions</a> |
| </h5></div></div></div> |
| <p> |
| Imagine your DSEL is a miniature I/O facility, with iostream operations |
| that execute lazily. You might want expressions representing input operations |
| to be processed by one function, and output operations to be processed |
| by a different function. How would you do that? |
| </p> |
| <p> |
| The answer is to write patterns (a.k.a, <span class="emphasis"><em>grammars</em></span>) |
| that match the structure of input and output expressions. Proto provides |
| utilities for defining the grammars, and the <code class="computeroutput"><a class="link" href="../boost/proto/matches.html" title="Struct template matches">proto::matches<></a></code> |
| template for checking whether a given expression type matches the grammar. |
| </p> |
| <p> |
| First, let's define some terminals we can use in our lazy I/O expressions: |
| </p> |
| <pre class="programlisting"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">istream</span> <span class="special">&</span> <span class="special">>::</span><span class="identifier">type</span> <span class="identifier">cin_</span> <span class="special">=</span> <span class="special">{</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cin</span> <span class="special">};</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span> <span class="special">>::</span><span class="identifier">type</span> <span class="identifier">cout_</span> <span class="special">=</span> <span class="special">{</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">};</span> |
| </pre> |
| <p> |
| Now, we can use <code class="computeroutput"><span class="identifier">cout_</span></code> |
| instead of <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span></code>, and get I/O expression trees |
| that we can execute later. To define grammars that match input and output |
| expressions of the form <code class="computeroutput"><span class="identifier">cin_</span> |
| <span class="special">>></span> <span class="identifier">i</span></code> |
| and <code class="computeroutput"><span class="identifier">cout_</span> <span class="special"><<</span> |
| <span class="number">1</span></code> we do this: |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">Input</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_right</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">istream</span> <span class="special">&</span> <span class="special">>,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span> <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">Output</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_left</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span> <span class="special">>,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span> <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| We've seen the template <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><></span></code> before, but here we're using |
| it without accessing the nested <code class="computeroutput"><span class="special">::</span><span class="identifier">type</span></code>. When used like this, it is a |
| very simple grammar, as are <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_right</span><span class="special"><></span></code> and <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_left</span><span class="special"><></span></code>. The newcomer here is <code class="computeroutput"><span class="identifier">_</span></code> in the <code class="computeroutput"><span class="identifier">proto</span></code> |
| namespace. It is a wildcard that matches anything. The <code class="computeroutput"><span class="identifier">Input</span></code> struct is a grammar that matches |
| any right-shift expression that has a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">istream</span></code> |
| terminal as its left operand. |
| </p> |
| <p> |
| We can use these grammars together with the <code class="computeroutput"><a class="link" href="../boost/proto/matches.html" title="Struct template matches">proto::matches<></a></code> |
| template to query at compile time whether a given I/O expression type |
| is an input or output operation. Consider the following: |
| </p> |
| <pre class="programlisting"><span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Expr</span> <span class="special">></span> |
| <span class="keyword">void</span> <span class="identifier">input_output</span><span class="special">(</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">expr</span> <span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">if</span><span class="special">(</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">Input</span> <span class="special">>::</span><span class="identifier">value</span> <span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"Input!\n"</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">if</span><span class="special">(</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">Output</span> <span class="special">>::</span><span class="identifier">value</span> <span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"Output!\n"</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="keyword">int</span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> |
| <span class="identifier">input_output</span><span class="special">(</span> <span class="identifier">cout_</span> <span class="special"><<</span> <span class="number">1</span> <span class="special">);</span> |
| <span class="identifier">input_output</span><span class="special">(</span> <span class="identifier">cin_</span> <span class="special">>></span> <span class="identifier">i</span> <span class="special">);</span> |
| |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| This program prints the following: |
| </p> |
| <pre class="programlisting">Output! |
| Input! |
| </pre> |
| <p> |
| If we wanted to break the <code class="computeroutput"><span class="identifier">input_output</span><span class="special">()</span></code> function into two functions, one that |
| handles input expressions and one for output expressions, we can use |
| <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">enable_if</span><span class="special"><></span></code>, |
| as follows: |
| </p> |
| <pre class="programlisting"><span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Expr</span> <span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">enable_if</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">Input</span> <span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> |
| <span class="identifier">input_output</span><span class="special">(</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">expr</span> <span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"Input!\n"</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Expr</span> <span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">enable_if</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">Output</span> <span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> |
| <span class="identifier">input_output</span><span class="special">(</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">expr</span> <span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"Output!\n"</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| This works as the previous version did. However, the following does not |
| compile at all: |
| </p> |
| <pre class="programlisting"><span class="identifier">input_output</span><span class="special">(</span> <span class="identifier">cout_</span> <span class="special"><<</span> <span class="number">1</span> <span class="special"><<</span> <span class="number">2</span> <span class="special">);</span> <span class="comment">// oops!</span> |
| </pre> |
| <p> |
| What's wrong? The problem is that this expression does not match our |
| grammar. The expression groups as if it were written like <code class="computeroutput"><span class="special">(</span><span class="identifier">cout_</span> <span class="special"><<</span> <span class="number">1</span><span class="special">)</span> <span class="special"><<</span> <span class="number">2</span></code>. It will not match the <code class="computeroutput"><span class="identifier">Output</span></code> grammar, which expects the left |
| operand to be a terminal, not another left-shift operation. We need to |
| fix the grammar. |
| </p> |
| <p> |
| We notice that in order to verify an expression as input or output, we'll |
| need to recurse down to the bottom-left-most leaf and check that it is |
| a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">istream</span></code> or <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span></code>. |
| When we get to the terminal, we must stop recursing. We can express this |
| in our grammar using <code class="computeroutput"><a class="link" href="../boost/proto/or_.html" title="Struct template or_">proto::or_<></a></code>. |
| Here are the correct <code class="computeroutput"><span class="identifier">Input</span></code> |
| and <code class="computeroutput"><span class="identifier">Output</span></code> grammars: |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">Input</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_right</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">istream</span> <span class="special">&</span> <span class="special">>,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_right</span><span class="special"><</span> <span class="identifier">Input</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span> <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">Output</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_left</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span> <span class="special">>,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_left</span><span class="special"><</span> <span class="identifier">Output</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span> <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| This may look a little odd at first. We seem to be defining the <code class="computeroutput"><span class="identifier">Input</span></code> and <code class="computeroutput"><span class="identifier">Output</span></code> |
| types in terms of themselves. This is perfectly OK, actually. At the |
| point in the grammar that the <code class="computeroutput"><span class="identifier">Input</span></code> |
| and <code class="computeroutput"><span class="identifier">Output</span></code> types are |
| being used, they are <span class="emphasis"><em>incomplete</em></span>, but by the time |
| we actually evaluate the grammar with <code class="computeroutput"><a class="link" href="../boost/proto/matches.html" title="Struct template matches">proto::matches<></a></code>, |
| the types will be complete. These are recursive grammars, and rightly |
| so because they must match a recursive data structure! |
| </p> |
| <p> |
| Matching an expression such as <code class="computeroutput"><span class="identifier">cout_</span> |
| <span class="special"><<</span> <span class="number">1</span> |
| <span class="special"><<</span> <span class="number">2</span></code> |
| against the <code class="computeroutput"><span class="identifier">Output</span></code> grammar |
| procedes as follows: |
| </p> |
| <div class="orderedlist"><ol class="orderedlist" type="1"> |
| <li class="listitem"> |
| The first alternate of the <code class="computeroutput"><a class="link" href="../boost/proto/or_.html" title="Struct template or_">proto::or_<></a></code> |
| is tried first. It will fail, because the expression <code class="computeroutput"><span class="identifier">cout_</span> <span class="special"><<</span> |
| <span class="number">1</span> <span class="special"><<</span> |
| <span class="number">2</span></code> does not match the grammar |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_left</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span> |
| <span class="special">>,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span> <span class="special">></span></code>. |
| </li> |
| <li class="listitem"> |
| Then the second alternate is tried next. We match the expression |
| against <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_left</span><span class="special"><</span> |
| <span class="identifier">Output</span><span class="special">,</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span> <span class="special">></span></code>. |
| The expression is a left-shift, so we next try to match the operands. |
| </li> |
| <li class="listitem"> |
| The right operand <code class="computeroutput"><span class="number">2</span></code> matches |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span></code> trivially. |
| </li> |
| <li class="listitem"> |
| To see if the left operand <code class="computeroutput"><span class="identifier">cout_</span> |
| <span class="special"><<</span> <span class="number">1</span></code> |
| matches <code class="computeroutput"><span class="identifier">Output</span></code>, we |
| must recursively evaluate the <code class="computeroutput"><span class="identifier">Output</span></code> |
| grammar. This time we succeed, because <code class="computeroutput"><span class="identifier">cout_</span> |
| <span class="special"><<</span> <span class="number">1</span></code> |
| will match the first alternate of the <code class="computeroutput"><a class="link" href="../boost/proto/or_.html" title="Struct template or_">proto::or_<></a></code>. |
| </li> |
| </ol></div> |
| <p> |
| We're done -- the grammar matches successfully. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.intermediate_form.expression_introspection.fuzzy_and_exact_matches_of_terminals"></a><a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.expression_introspection.fuzzy_and_exact_matches_of_terminals" title="Fuzzy and Exact Matches of Terminals">Fuzzy |
| and Exact Matches of Terminals</a> |
| </h5></div></div></div> |
| <p> |
| The terminals in an expression tree could be const or non-const references, |
| or they might not be references at all. When writing grammars, you usually |
| don't have to worry about it because <code class="computeroutput"><a class="link" href="../boost/proto/matches.html" title="Struct template matches">proto::matches<></a></code> |
| gives you a little wiggle room when matching terminals. A grammar such |
| as <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span></code> |
| will match a terminal of type <code class="computeroutput"><span class="keyword">int</span></code>, |
| <code class="computeroutput"><span class="keyword">int</span> <span class="special">&</span></code>, |
| or <code class="computeroutput"><span class="keyword">int</span> <span class="keyword">const</span> |
| <span class="special">&</span></code>. |
| </p> |
| <p> |
| You can explicitly specify that you want to match a reference type. If |
| you do, the type must match exactly. For instance, a grammar such as |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span> <span class="special">&></span></code> |
| will only match an <code class="computeroutput"><span class="keyword">int</span> <span class="special">&</span></code>. It will not match an <code class="computeroutput"><span class="keyword">int</span></code> or an <code class="computeroutput"><span class="keyword">int</span> |
| <span class="keyword">const</span> <span class="special">&</span></code>. |
| </p> |
| <p> |
| The table below shows how Proto matches terminals. The simple rule is: |
| if you want to match only reference types, you must specify the reference |
| in your grammar. Otherwise, leave it off and Proto will ignore const |
| and references. |
| </p> |
| <div class="table"> |
| <a name="id2317416"></a><p class="title"><b>Table 16.6. proto::matches<> and Reference / CV-Qualification of Terminals</b></p> |
| <div class="table-contents"><table class="table" summary="proto::matches<> and Reference / CV-Qualification of Terminals"> |
| <colgroup> |
| <col> |
| <col> |
| <col> |
| </colgroup> |
| <thead><tr> |
| <th> |
| <p> |
| Terminal |
| </p> |
| </th> |
| <th> |
| <p> |
| Grammar |
| </p> |
| </th> |
| <th> |
| <p> |
| Matches? |
| </p> |
| </th> |
| </tr></thead> |
| <tbody> |
| <tr> |
| <td> |
| <p> |
| T |
| </p> |
| </td> |
| <td> |
| <p> |
| T |
| </p> |
| </td> |
| <td> |
| <p> |
| yes |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| T & |
| </p> |
| </td> |
| <td> |
| <p> |
| T |
| </p> |
| </td> |
| <td> |
| <p> |
| yes |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| T const & |
| </p> |
| </td> |
| <td> |
| <p> |
| T |
| </p> |
| </td> |
| <td> |
| <p> |
| yes |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| T |
| </p> |
| </td> |
| <td> |
| <p> |
| T & |
| </p> |
| </td> |
| <td> |
| <p> |
| no |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| T & |
| </p> |
| </td> |
| <td> |
| <p> |
| T & |
| </p> |
| </td> |
| <td> |
| <p> |
| yes |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| T const & |
| </p> |
| </td> |
| <td> |
| <p> |
| T & |
| </p> |
| </td> |
| <td> |
| <p> |
| no |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| T |
| </p> |
| </td> |
| <td> |
| <p> |
| T const & |
| </p> |
| </td> |
| <td> |
| <p> |
| no |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| T & |
| </p> |
| </td> |
| <td> |
| <p> |
| T const & |
| </p> |
| </td> |
| <td> |
| <p> |
| no |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| T const & |
| </p> |
| </td> |
| <td> |
| <p> |
| T const & |
| </p> |
| </td> |
| <td> |
| <p> |
| yes |
| </p> |
| </td> |
| </tr> |
| </tbody> |
| </table></div> |
| </div> |
| <br class="table-break"><p> |
| This begs the question: What if you want to match an <code class="computeroutput"><span class="keyword">int</span></code>, |
| but not an <code class="computeroutput"><span class="keyword">int</span> <span class="special">&</span></code> |
| or an <code class="computeroutput"><span class="keyword">int</span> <span class="keyword">const</span> |
| <span class="special">&</span></code>? For forcing exact matches, |
| Proto provides the <code class="computeroutput"><a class="link" href="../boost/proto/exact.html" title="Struct template exact">proto::exact<></a></code> |
| template. For instance, <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">exact</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="special">></span></code> |
| would only match an <code class="computeroutput"><span class="keyword">int</span></code> |
| held by value. |
| </p> |
| <p> |
| Proto gives you extra wiggle room when matching array types. Array types |
| match themselves or the pointer types they decay to. This is especially |
| useful with character arrays. The type returned by <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special">(</span><span class="string">"hello"</span><span class="special">)</span></code> is <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">char</span> <span class="keyword">const</span><span class="special">[</span><span class="number">6</span><span class="special">]>::</span><span class="identifier">type</span></code>. That's a terminal containing |
| a 6-element character array. Naturally, you can match this terminal with |
| the grammar <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">char</span> <span class="keyword">const</span><span class="special">[</span><span class="number">6</span><span class="special">]></span></code>, |
| but the grammar <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">char</span> <span class="keyword">const</span> <span class="special">*></span></code> |
| will match it as well, as the following code fragment illustrates. |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">CharString</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="keyword">char</span> <span class="keyword">const</span> <span class="special">*</span> <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">typedef</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="keyword">char</span> <span class="keyword">const</span><span class="special">[</span><span class="number">6</span><span class="special">]</span> <span class="special">>::</span><span class="identifier">type</span> <span class="identifier">char_array</span><span class="special">;</span> |
| |
| <span class="identifier">BOOST_MPL_ASSERT</span><span class="special">((</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span> <span class="identifier">char_array</span><span class="special">,</span> <span class="identifier">CharString</span> <span class="special">></span> <span class="special">));</span> |
| </pre> |
| <p> |
| What if we only wanted <code class="computeroutput"><span class="identifier">CharString</span></code> |
| to match terminals of exactly the type <code class="computeroutput"><span class="keyword">char</span> |
| <span class="keyword">const</span> <span class="special">*</span></code>? |
| You can use <code class="computeroutput"><a class="link" href="../boost/proto/exact.html" title="Struct template exact">proto::exact<></a></code> here to turn off |
| the fuzzy matching of terminals, as follows: |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">CharString</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">exact</span><span class="special"><</span> <span class="keyword">char</span> <span class="keyword">const</span> <span class="special">*</span> <span class="special">></span> <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">typedef</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">char</span> <span class="keyword">const</span><span class="special">[</span><span class="number">6</span><span class="special">]>::</span><span class="identifier">type</span> <span class="identifier">char_array</span><span class="special">;</span> |
| <span class="keyword">typedef</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">char</span> <span class="keyword">const</span> <span class="special">*>::</span><span class="identifier">type</span> <span class="identifier">char_string</span><span class="special">;</span> |
| |
| <span class="identifier">BOOST_MPL_ASSERT</span><span class="special">((</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span> <span class="identifier">char_string</span><span class="special">,</span> <span class="identifier">CharString</span> <span class="special">></span> <span class="special">));</span> |
| <span class="identifier">BOOST_MPL_ASSERT_NOT</span><span class="special">((</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span> <span class="identifier">char_array</span><span class="special">,</span> <span class="identifier">CharString</span> <span class="special">></span> <span class="special">));</span> |
| </pre> |
| <p> |
| Now, <code class="computeroutput"><span class="identifier">CharString</span></code> does |
| not match array types, only character string pointers. |
| </p> |
| <p> |
| The inverse problem is a little trickier: what if you wanted to match |
| all character arrays, but not character pointers? As mentioned above, |
| the expression <code class="computeroutput"><span class="identifier">as_expr</span><span class="special">(</span><span class="string">"hello"</span><span class="special">)</span></code> has the type <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="keyword">char</span> <span class="keyword">const</span><span class="special">[</span> <span class="number">6</span> <span class="special">]</span> <span class="special">>::</span><span class="identifier">type</span></code>. If you wanted to match character |
| arrays of arbitrary size, you could use <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">N</span></code>, |
| which is an array-size wildcard. The following grammar would match any |
| string literal: <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="keyword">char</span> <span class="keyword">const</span><span class="special">[</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">N</span> <span class="special">]</span> <span class="special">></span></code>. |
| </p> |
| <p> |
| Sometimes you need even more wiggle room when matching terminals. For |
| example, maybe you're building a calculator DSEL and you want to allow |
| any terminals that are convertible to <code class="computeroutput"><span class="keyword">double</span></code>. |
| For that, Proto provides the <code class="computeroutput"><a class="link" href="../boost/proto/convertible_to.html" title="Struct template convertible_to">proto::convertible_to<></a></code> |
| template. You can use it as: <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">convertible_to</span><span class="special"><</span> <span class="keyword">double</span> |
| <span class="special">></span> <span class="special">></span></code>. |
| </p> |
| <p> |
| There is one more way you can perform a fuzzy match on terminals. Consider |
| the problem of trying to match a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">complex</span><span class="special"><></span></code> terminal. You can easily match |
| a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">complex</span><span class="special"><</span><span class="keyword">float</span><span class="special">></span></code> |
| or a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">complex</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span></code>, |
| but how would you match any instantiation of <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">complex</span><span class="special"><></span></code>? You can use <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span></code> |
| here to solve this problem. Here is the grammar to match any <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">complex</span><span class="special"><></span></code> |
| instantiation: |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">StdComplex</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">complex</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span> <span class="special">></span> <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| When given a grammar like this, Proto will deconstruct the grammar and |
| the terminal it is being matched against and see if it can match all |
| the constituents. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.intermediate_form.expression_introspection.if_and_not"></a><a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.expression_introspection.if_and_not" title="if_<>, and_<>, and not_<>"><code class="literal">if_<></code>, |
| <code class="literal">and_<></code>, and <code class="literal">not_<></code></a> |
| </h5></div></div></div> |
| <p> |
| We've already seen how to use expression generators like <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><></span></code> |
| and <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_right</span><span class="special"><></span></code> |
| as grammars. We've also seen <code class="computeroutput"><a class="link" href="../boost/proto/or_.html" title="Struct template or_">proto::or_<></a></code>, |
| which we can use to express a set of alternate grammars. There are a |
| few others of interest; in particular, <code class="computeroutput"><a class="link" href="../boost/proto/if_.html" title="Struct template if_">proto::if_<></a></code>, |
| <code class="computeroutput"><a class="link" href="../boost/proto/and_.html" title="Struct template and_">proto::and_<></a></code> and <code class="computeroutput"><a class="link" href="../boost/proto/not_.html" title="Struct template not_">proto::not_<></a></code>. |
| </p> |
| <p> |
| The <code class="computeroutput"><a class="link" href="../boost/proto/not_.html" title="Struct template not_">proto::not_<></a></code> template is the simplest. |
| It takes a grammar as a template parameter and logically negates it; |
| <code class="computeroutput"><span class="identifier">not_</span><span class="special"><</span><span class="identifier">Grammar</span><span class="special">></span></code> |
| will match any expression that <code class="computeroutput"><span class="identifier">Grammar</span></code> |
| does <span class="emphasis"><em>not</em></span> match. |
| </p> |
| <p> |
| The <code class="computeroutput"><a class="link" href="../boost/proto/if_.html" title="Struct template if_">proto::if_<></a></code> template is used |
| together with a Proto transform that is evaluated against expression |
| types to find matches. (Proto transforms will be described later.) |
| </p> |
| <p> |
| The <code class="computeroutput"><a class="link" href="../boost/proto/and_.html" title="Struct template and_">proto::and_<></a></code> template is like |
| <code class="computeroutput"><a class="link" href="../boost/proto/or_.html" title="Struct template or_">proto::or_<></a></code>, except that each |
| argument of the <code class="computeroutput"><a class="link" href="../boost/proto/and_.html" title="Struct template and_">proto::and_<></a></code> must match in order |
| for the <code class="computeroutput"><a class="link" href="../boost/proto/and_.html" title="Struct template and_">proto::and_<></a></code> to match. As an example, |
| consider the definition of <code class="computeroutput"><span class="identifier">CharString</span></code> |
| above that uses <code class="computeroutput"><a class="link" href="../boost/proto/exact.html" title="Struct template exact">proto::exact<></a></code>. It could have been |
| written without <code class="computeroutput"><a class="link" href="../boost/proto/exact.html" title="Struct template exact">proto::exact<></a></code> as follows: |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">CharString</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">and_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">if_</span><span class="special"><</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">is_same</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">,</span> <span class="keyword">char</span> <span class="keyword">const</span> <span class="special">*</span> <span class="special">>()</span> <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| This says that a <code class="computeroutput"><span class="identifier">CharString</span></code> |
| must be a terminal, <span class="emphasis"><em>and</em></span> its value type must be the |
| same as <code class="computeroutput"><span class="keyword">char</span> <span class="keyword">const</span> |
| <span class="special">*</span></code>. Notice the template argument |
| of <code class="computeroutput"><a class="link" href="../boost/proto/if_.html" title="Struct template if_">proto::if_<></a></code>: <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">is_same</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">,</span> <span class="keyword">char</span> <span class="keyword">const</span> <span class="special">*</span> <span class="special">>()</span></code>. This is Proto transform that compares |
| the value type of a terminal to <code class="computeroutput"><span class="keyword">char</span> |
| <span class="keyword">const</span> <span class="special">*</span></code>. |
| </p> |
| <p> |
| The <code class="computeroutput"><a class="link" href="../boost/proto/if_.html" title="Struct template if_">proto::if_<></a></code> template has a couple |
| of variants. In addition to <code class="computeroutput"><span class="identifier">if_</span><span class="special"><</span><span class="identifier">Condition</span><span class="special">></span></code> you can also say <code class="computeroutput"><span class="identifier">if_</span><span class="special"><</span><span class="identifier">Condition</span><span class="special">,</span> <span class="identifier">ThenGrammar</span><span class="special">></span></code> and <code class="computeroutput"><span class="identifier">if_</span><span class="special"><</span><span class="identifier">Condition</span><span class="special">,</span> <span class="identifier">ThenGrammar</span><span class="special">,</span> <span class="identifier">ElseGrammar</span><span class="special">></span></code>. These let you select one sub-grammar |
| or another based on the <code class="computeroutput"><span class="identifier">Condition</span></code>. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.intermediate_form.expression_introspection.switch"></a><a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.expression_introspection.switch" title="Improving Compile Times With switch_<>">Improving |
| Compile Times With <code class="literal">switch_<></code></a> |
| </h5></div></div></div> |
| <p> |
| When your Proto grammar gets large, you'll start to run into some scalability |
| problems with <code class="computeroutput"><a class="link" href="../boost/proto/or_.html" title="Struct template or_">proto::or_<></a></code>, the construct you |
| use to specify alternate sub-grammars. First, due to limitations in C++, |
| <code class="computeroutput"><a class="link" href="../boost/proto/or_.html" title="Struct template or_">proto::or_<></a></code> can only accept up |
| to a certain number of sub-grammars, controlled by the <code class="computeroutput"><span class="identifier">BOOST_PROTO_MAX_LOGICAL_ARITY</span></code> macro. |
| This macro defaults to eight, and you can set it higher, but doing so |
| will aggravate another scalability problem: long compile times. With |
| <code class="computeroutput"><a class="link" href="../boost/proto/or_.html" title="Struct template or_">proto::or_<></a></code>, alternate sub-grammars |
| are tried in order -- like a series of cascading <code class="computeroutput"><span class="keyword">if</span></code>'s |
| -- leading to lots of unnecessary template instantiations. What you would |
| prefer instead is something like <code class="computeroutput"><span class="keyword">switch</span></code> |
| that avoids the expense of cascading <code class="computeroutput"><span class="keyword">if</span></code>'s. |
| That's the purpose of <code class="computeroutput"><a class="link" href="../boost/proto/switch_.html" title="Struct template switch_">proto::switch_<></a></code>; |
| although less convenient than <code class="computeroutput"><a class="link" href="../boost/proto/or_.html" title="Struct template or_">proto::or_<></a></code>, |
| it improves compile times for larger grammars and does not have an arbitrary |
| fixed limit on the number of sub-grammars. |
| </p> |
| <p> |
| Let's illustrate how to use <code class="computeroutput"><a class="link" href="../boost/proto/switch_.html" title="Struct template switch_">proto::switch_<></a></code> |
| by first writing a big grammar with <code class="computeroutput"><a class="link" href="../boost/proto/or_.html" title="Struct template or_">proto::or_<></a></code> |
| and then translating it to an equivalent grammar using <code class="computeroutput"><a class="link" href="../boost/proto/switch_.html" title="Struct template switch_">proto::switch_<></a></code>: |
| </p> |
| <pre class="programlisting"><span class="comment">// Here is a big, inefficient grammar</span> |
| <span class="keyword">struct</span> <span class="identifier">ABigGrammar</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">unary_plus</span><span class="special"><</span><span class="identifier">ABigGrammar</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">negate</span><span class="special"><</span><span class="identifier">ABigGrammar</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">complement</span><span class="special"><</span><span class="identifier">ABigGrammar</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><span class="identifier">ABigGrammar</span><span class="special">,</span> <span class="identifier">ABigGrammar</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">minus</span><span class="special"><</span><span class="identifier">ABigGrammar</span><span class="special">,</span> <span class="identifier">ABigGrammar</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">multiplies</span><span class="special"><</span><span class="identifier">ABigGrammar</span><span class="special">,</span> <span class="identifier">ABigGrammar</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">divides</span><span class="special"><</span><span class="identifier">ABigGrammar</span><span class="special">,</span> <span class="identifier">ABigGrammar</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">modulus</span><span class="special"><</span><span class="identifier">ABigGrammar</span><span class="special">,</span> <span class="identifier">ABigGrammar</span><span class="special">></span> |
| <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| The above might be the grammar to a more elaborate calculator DSEL. Notice |
| that since there are more than eight sub-grammars, we had to chain the |
| sub-grammars with a nested <code class="computeroutput"><a class="link" href="../boost/proto/or_.html" title="Struct template or_">proto::or_<></a></code> |
| -- not very nice. |
| </p> |
| <p> |
| The idea behind <code class="computeroutput"><a class="link" href="../boost/proto/switch_.html" title="Struct template switch_">proto::switch_<></a></code> |
| is to dispatch based on an expression's tag type to a sub-grammar that |
| handles expressions of that type. To use <code class="computeroutput"><a class="link" href="../boost/proto/switch_.html" title="Struct template switch_">proto::switch_<></a></code>, |
| you define a struct with a nested <code class="computeroutput"><span class="identifier">case_</span><span class="special"><></span></code> template, specialized on tag |
| types. The above grammar can be expressed using <code class="computeroutput"><a class="link" href="../boost/proto/switch_.html" title="Struct template switch_">proto::switch_<></a></code> |
| as follows. It is described below. |
| </p> |
| <pre class="programlisting"><span class="comment">// Redefine ABigGrammar more efficiently using proto::switch_<></span> |
| <span class="keyword">struct</span> <span class="identifier">ABigGrammar</span><span class="special">;</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">ABigGrammarCases</span> |
| <span class="special">{</span> |
| <span class="comment">// The primary template matches nothing:</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Tag</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">case_</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">not_</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> |
| <span class="special">{};</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Terminal expressions are handled here</span> |
| <span class="keyword">template</span><span class="special"><></span> |
| <span class="keyword">struct</span> <span class="identifier">ABigGrammarCases</span><span class="special">::</span><span class="identifier">case_</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">></span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Non-terminals are handled similarly</span> |
| <span class="keyword">template</span><span class="special"><></span> |
| <span class="keyword">struct</span> <span class="identifier">ABigGrammarCases</span><span class="special">::</span><span class="identifier">case_</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">unary_plus</span><span class="special">></span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">unary_plus</span><span class="special"><</span><span class="identifier">ABigGrammar</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><></span> |
| <span class="keyword">struct</span> <span class="identifier">ABigGrammarCases</span><span class="special">::</span><span class="identifier">case_</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">negate</span><span class="special">></span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">negate</span><span class="special"><</span><span class="identifier">ABigGrammar</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><></span> |
| <span class="keyword">struct</span> <span class="identifier">ABigGrammarCases</span><span class="special">::</span><span class="identifier">case_</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">complement</span><span class="special">></span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">complement</span><span class="special"><</span><span class="identifier">ABigGrammar</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><></span> |
| <span class="keyword">struct</span> <span class="identifier">ABigGrammarCases</span><span class="special">::</span><span class="identifier">case_</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">plus</span><span class="special">></span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><span class="identifier">ABigGrammar</span><span class="special">,</span> <span class="identifier">ABigGrammar</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><></span> |
| <span class="keyword">struct</span> <span class="identifier">ABigGrammarCases</span><span class="special">::</span><span class="identifier">case_</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">minus</span><span class="special">></span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">minus</span><span class="special"><</span><span class="identifier">ABigGrammar</span><span class="special">,</span> <span class="identifier">ABigGrammar</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><></span> |
| <span class="keyword">struct</span> <span class="identifier">ABigGrammarCases</span><span class="special">::</span><span class="identifier">case_</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">multiplies</span><span class="special">></span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">multiplies</span><span class="special"><</span><span class="identifier">ABigGrammar</span><span class="special">,</span> <span class="identifier">ABigGrammar</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><></span> |
| <span class="keyword">struct</span> <span class="identifier">ABigGrammarCases</span><span class="special">::</span><span class="identifier">case_</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">divides</span><span class="special">></span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">divides</span><span class="special"><</span><span class="identifier">ABigGrammar</span><span class="special">,</span> <span class="identifier">ABigGrammar</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><></span> |
| <span class="keyword">struct</span> <span class="identifier">ABigGrammarCases</span><span class="special">::</span><span class="identifier">case_</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">modulus</span><span class="special">></span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">modulus</span><span class="special"><</span><span class="identifier">ABigGrammar</span><span class="special">,</span> <span class="identifier">ABigGrammar</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Define ABigGrammar in terms of ABigGrammarCases</span> |
| <span class="comment">// using proto::switch_<></span> |
| <span class="keyword">struct</span> <span class="identifier">ABigGrammar</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">switch_</span><span class="special"><</span><span class="identifier">ABigGrammarCases</span><span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| Matching an expression type <code class="computeroutput"><span class="identifier">E</span></code> |
| against <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">switch_</span><span class="special"><</span><span class="identifier">C</span><span class="special">></span></code> |
| is equivalent to matching it against <code class="computeroutput"><span class="identifier">C</span><span class="special">::</span><span class="identifier">case_</span><span class="special"><</span><span class="identifier">E</span><span class="special">::</span><span class="identifier">proto_tag</span><span class="special">></span></code>. By dispatching on the expression's |
| tag type, we can jump to the sub-grammar that handles expressions of |
| that type, skipping over all the other sub-grammars that couldn't possibly |
| match. If there is no specialization of <code class="computeroutput"><span class="identifier">case_</span><span class="special"><></span></code> for a particular tag type, we |
| select the primary template. In this case, the primary template inherits |
| from <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">not_</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span></code> |
| which matches no expressions. |
| </p> |
| <p> |
| Notice the specialization that handles terminals: |
| </p> |
| <pre class="programlisting"><span class="comment">// Terminal expressions are handled here</span> |
| <span class="keyword">template</span><span class="special"><></span> |
| <span class="keyword">struct</span> <span class="identifier">ABigGrammarCases</span><span class="special">::</span><span class="identifier">case_</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">></span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| The <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span></code> type by itself isn't enough |
| to select an appropriate sub-grammar, so we use <code class="computeroutput"><a class="link" href="../boost/proto/or_.html" title="Struct template or_">proto::or_<></a></code> |
| to list the alternate sub-grammars that match terminals. |
| </p> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"> |
| <p> |
| You might be tempted to define your <code class="computeroutput"><span class="identifier">case_</span><span class="special"><></span></code> specializations <span class="emphasis"><em>in |
| situ</em></span> as follows: |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">ABigGrammarCases</span> |
| <span class="special">{</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Tag</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">case_</span> <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">not_</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> <span class="special">{};</span> |
| |
| <span class="comment">// ERROR: not legal C++</span> |
| <span class="keyword">template</span><span class="special"><></span> |
| <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">></span> |
| <span class="comment">/* ... */</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| </p> |
| <p> |
| Unfortunately, for arcane reasons, it is not legal to define an explicit |
| nested specialization <span class="emphasis"><em>in situ</em></span> like this. It is, |
| however, perfectly legal to define <span class="emphasis"><em>partial</em></span> specializations |
| <span class="emphasis"><em>in situ</em></span>, so you can add a extra dummy template |
| parameter that has a default, as follows: |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">ABigGrammarCases</span> |
| <span class="special">{</span> |
| <span class="comment">// Note extra "Dummy" template parameter here:</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Tag</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">Dummy</span> <span class="special">=</span> <span class="number">0</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">case_</span> <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">not_</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> <span class="special">{};</span> |
| |
| <span class="comment">// OK: "Dummy" makes this a partial specialization</span> |
| <span class="comment">// instead of an explicit specialization.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">Dummy</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">,</span> <span class="identifier">Dummy</span><span class="special">></span> |
| <span class="comment">/* ... */</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| </p> |
| <p> |
| You might find this cleaner than defining explicit <code class="computeroutput"><span class="identifier">case_</span><span class="special"><></span></code> specializations outside of |
| their enclosing struct. |
| </p> |
| </td></tr> |
| </table></div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.intermediate_form.expression_introspection.matching_vararg_expressions"></a><a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.expression_introspection.matching_vararg_expressions" title="Matching Vararg Expressions">Matching |
| Vararg Expressions</a> |
| </h5></div></div></div> |
| <p> |
| Not all of C++'s overloadable operators are unary or binary. There is |
| the oddball <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code> |
| -- the function call operator -- which can have any number of arguments. |
| Likewise, with Proto you may define your own "operators" that |
| could also take more that two arguments. As a result, there may be nodes |
| in your Proto expression tree that have an arbitrary number of children |
| (up to <code class="literal"><code class="computeroutput"><a class="link" href="../BOOST_PROTO_MAX_ARITY.html" title="Macro BOOST_PROTO_MAX_ARITY">BOOST_PROTO_MAX_ARITY</a></code></code>, |
| which is configurable). How do you write a grammar to match such a node? |
| </p> |
| <p> |
| For such cases, Proto provides the <code class="computeroutput"><a class="link" href="../boost/proto/vararg.html" title="Struct template vararg">proto::vararg<></a></code> |
| class template. Its template argument is a grammar, and the <code class="computeroutput"><a class="link" href="../boost/proto/vararg.html" title="Struct template vararg">proto::vararg<></a></code> will match the grammar |
| zero or more times. Consider a Proto lazy function called <code class="computeroutput"><span class="identifier">fun</span><span class="special">()</span></code> |
| that can take zero or more characters as arguments, as follows: |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">fun_tag</span> <span class="special">{};</span> |
| <span class="keyword">struct</span> <span class="identifier">FunTag</span> <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">fun_tag</span> <span class="special">></span> <span class="special">{};</span> |
| <span class="identifier">FunTag</span><span class="special">::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">fun</span> <span class="special">=</span> <span class="special">{{}};</span> |
| |
| <span class="comment">// example usage:</span> |
| <span class="identifier">fun</span><span class="special">();</span> |
| <span class="identifier">fun</span><span class="special">(</span><span class="char">'a'</span><span class="special">);</span> |
| <span class="identifier">fun</span><span class="special">(</span><span class="char">'a'</span><span class="special">,</span> <span class="char">'b'</span><span class="special">);</span> |
| <span class="special">...</span> |
| </pre> |
| <p> |
| Below is the grammar that matches all the allowable invocations of <code class="computeroutput"><span class="identifier">fun</span><span class="special">()</span></code>: |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">FunCall</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">function</span><span class="special"><</span> <span class="identifier">FunTag</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">vararg</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="keyword">char</span> <span class="special">></span> <span class="special">></span> <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| The <code class="computeroutput"><span class="identifier">FunCall</span></code> grammar uses |
| <code class="computeroutput"><a class="link" href="../boost/proto/vararg.html" title="Struct template vararg">proto::vararg<></a></code> to match zero or |
| more character literals as arguments of the <code class="computeroutput"><span class="identifier">fun</span><span class="special">()</span></code> function. |
| </p> |
| <p> |
| As another example, can you guess what the following grammar matches? |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">Foo</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">nary_expr</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">vararg</span><span class="special"><</span> <span class="identifier">Foo</span> <span class="special">></span> <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| Here's a hint: the first template parameter to <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">nary_expr</span><span class="special"><></span></code> represents the node type, and |
| any additional template parameters represent child nodes. The answer |
| is that this is a degenerate grammar that matches every possible expression |
| tree, from root to leaves. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.intermediate_form.expression_introspection.defining_dsel_grammars"></a><a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.expression_introspection.defining_dsel_grammars" title="Defining DSEL Grammars">Defining |
| DSEL Grammars</a> |
| </h5></div></div></div> |
| <p> |
| In this section we'll see how to use Proto to define a grammar for your |
| DSEL and use it to validate expression templates, giving short, readable |
| compile-time errors for invalid expressions. |
| </p> |
| <div class="tip"><table border="0" summary="Tip"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="../../../doc/src/images/tip.png"></td> |
| <th align="left">Tip</th> |
| </tr> |
| <tr><td align="left" valign="top"> |
| <p> |
| You might think that this is a backwards way of doing things. <span class="quote">“<span class="quote">If |
| Proto let me select which operators to overload, my users wouldn't |
| be able to create invalid expressions in the first place, and I wouldn't |
| need a grammar at all!</span>”</span> That may be true, but there are reasons |
| for preferring to do things this way. |
| </p> |
| <p> |
| First, it lets you develop your DSEL rapidly -- all the operators are |
| there for you already! -- and worry about invalid syntax later. |
| </p> |
| <p> |
| Second, it might be the case that some operators are only allowed in |
| certain contexts within your DSEL. This is easy to express with a grammar, |
| and hard to do with straight operator overloading. |
| </p> |
| <p> |
| Third, using a DSEL grammar to flag invalid expressions can often yield |
| better errors than manually selecting the overloaded operators. |
| </p> |
| <p> |
| Fourth, the grammar can be used for more than just validation. You |
| can use your grammar to define <span class="emphasis"><em>tree transformations</em></span> |
| that convert expression templates into other more useful objects. |
| </p> |
| <p> |
| If none of the above convinces you, you actually <span class="emphasis"><em>can</em></span> |
| use Proto to control which operators are overloaded within your domain. |
| And to do it, you need to define a grammar! |
| </p> |
| </td></tr> |
| </table></div> |
| <p> |
| In a previous section, we used Proto to define a DSEL for a lazily evaluated |
| calculator that allowed any combination of placeholders, floating-point |
| literals, addition, subtraction, multiplication, division and grouping. |
| If we were to write the grammar for this DSEL in <a href="http://en.wikipedia.org/wiki/Extended_Backus_Naur_Form" target="_top">EBNF</a>, |
| it might look like this: |
| </p> |
| <pre class="programlisting">group ::= '(' expression ')' |
| factor ::= double | '_1' | '_2' | group |
| term ::= factor (('*' factor) | ('/' factor))* |
| expression ::= term (('+' term) | ('-' term))* |
| </pre> |
| <p> |
| This captures the syntax, associativity and precedence rules of a calculator. |
| Writing the grammar for our calculator DSEL using Proto is <span class="emphasis"><em>even |
| simpler</em></span>. Since we are using C++ as the host language, we are |
| bound to the associativity and precedence rules for the C++ operators. |
| Our grammar can assume them. Also, in C++ grouping is already handled |
| for us with the use of parenthesis, so we don't have to code that into |
| our grammar. |
| </p> |
| <p> |
| Let's begin our grammar for forward-declaring it: |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">CalculatorGrammar</span><span class="special">;</span> |
| </pre> |
| <p> |
| It's an incomplete type at this point, but we'll still be able to use |
| it to define the rules of our grammar. Let's define grammar rules for |
| the terminals: |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">Double</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">convertible_to</span><span class="special"><</span> <span class="keyword">double</span> <span class="special">></span> <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">Placeholder1</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="number">0</span><span class="special">></span> <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">Placeholder2</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="number">1</span><span class="special">></span> <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">Terminal</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> <span class="identifier">Double</span><span class="special">,</span> <span class="identifier">Placeholder1</span><span class="special">,</span> <span class="identifier">Placeholder2</span> <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| Now let's define the rules for addition, subtraction, multiplication |
| and division. Here, we can ignore issues of associativity and precedence |
| -- the C++ compiler will enforce that for us. We only must enforce that |
| the arguments to the operators must themselves conform to the <code class="computeroutput"><span class="identifier">CalculatorGrammar</span></code> that we forward-declared |
| above. |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">Plus</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span> <span class="identifier">CalculatorGrammar</span><span class="special">,</span> <span class="identifier">CalculatorGrammar</span> <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">Minus</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">minus</span><span class="special"><</span> <span class="identifier">CalculatorGrammar</span><span class="special">,</span> <span class="identifier">CalculatorGrammar</span> <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">Multiplies</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">multiplies</span><span class="special"><</span> <span class="identifier">CalculatorGrammar</span><span class="special">,</span> <span class="identifier">CalculatorGrammar</span> <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">Divides</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">divides</span><span class="special"><</span> <span class="identifier">CalculatorGrammar</span><span class="special">,</span> <span class="identifier">CalculatorGrammar</span> <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| Now that we've defined all the parts of the grammar, we can define <code class="computeroutput"><span class="identifier">CalculatorGrammar</span></code>: |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">CalculatorGrammar</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">Terminal</span> |
| <span class="special">,</span> <span class="identifier">Plus</span> |
| <span class="special">,</span> <span class="identifier">Minus</span> |
| <span class="special">,</span> <span class="identifier">Multiplies</span> |
| <span class="special">,</span> <span class="identifier">Divides</span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| That's it! Now we can use <code class="computeroutput"><span class="identifier">CalculatorGrammar</span></code> |
| to enforce that an expression template conforms to our grammar. We can |
| use <code class="computeroutput"><a class="link" href="../boost/proto/matches.html" title="Struct template matches">proto::matches<></a></code> and <code class="computeroutput"><span class="identifier">BOOST_MPL_ASSERT</span><span class="special">()</span></code> |
| to issue readable compile-time errors for invalid expressions, as below: |
| </p> |
| <pre class="programlisting"><span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Expr</span> <span class="special">></span> |
| <span class="keyword">void</span> <span class="identifier">evaluate</span><span class="special">(</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">expr</span> <span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">BOOST_MPL_ASSERT</span><span class="special">((</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">CalculatorGrammar</span> <span class="special">></span> <span class="special">));</span> |
| <span class="comment">// ...</span> |
| <span class="special">}</span> |
| </pre> |
| </div> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="boost_proto.users_guide.back_end"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end" title="Back Ends: Making Expression Templates Do Useful Work">Back Ends: Making Expression |
| Templates Do Useful Work</a> |
| </h3></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end.expression_evaluation">Expression |
| Evaluation: Imparting Behaviors with a Context</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation">Expression |
| Transformation: Semantic Actions</a></span></dt> |
| </dl></div> |
| <p> |
| Now that you've written the front end for your DSEL compiler, and you've |
| learned a bit about the intermediate form it produces, it's time to think |
| about what to <span class="emphasis"><em>do</em></span> with the intermediate form. This is |
| where you put your domain-specific algorithms and optimizations. Proto gives |
| you two ways to evaluate and manipulate expression templates: contexts and |
| transforms. |
| </p> |
| <div class="itemizedlist"><ul class="itemizedlist" type="disc"> |
| <li class="listitem"> |
| A <span class="emphasis"><em>context</em></span> is like a function object that you pass |
| along with an expression to the <code class="computeroutput"><a class="link" href="../boost/proto/eval_id1354297.html" title="Function eval">proto::eval()</a></code> |
| function. It associates behaviors with node types. <code class="computeroutput"><a class="link" href="../boost/proto/eval_id1354297.html" title="Function eval">proto::eval()</a></code> |
| walks the expression and invokes your context at each node. |
| </li> |
| <li class="listitem"> |
| A <span class="emphasis"><em>transform</em></span> is a way to associate behaviors, not |
| with node types in an expression, but with rules in a Proto grammar. |
| In this way, they are like semantic actions in other compiler-construction |
| toolkits. |
| </li> |
| </ul></div> |
| <p> |
| Two ways to evaluate expressions! How to choose? Since contexts are largely |
| procedural, they are a bit simpler to understand and debug so they are a |
| good place to start. But although transforms are more advanced, they are |
| also more powerful; since they are associated with rules in your grammar, |
| you can select the proper transform based on the entire <span class="emphasis"><em>structure</em></span> |
| of a sub-expression rather than simply on the type of its top-most node. |
| </p> |
| <p> |
| Also, transforms have a concise and declarative syntax that can be confusing |
| at first, but highly expressive and fungible once you become accustomed to |
| it. And -- this is admittedly very subjective -- the author finds programming |
| with Proto transforms to be an inordinate amount of <span class="emphasis"><em>fun!</em></span> |
| Your mileage may vary. |
| </p> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_evaluation"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_evaluation" title="Expression Evaluation: Imparting Behaviors with a Context">Expression |
| Evaluation: Imparting Behaviors with a Context</a> |
| </h4></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end.expression_evaluation.proto_eval">Evaluating |
| an Expression with <code class="literal">proto::eval()</code></a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end.expression_evaluation.contexts">Defining |
| an Evaluation Context</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end.expression_evaluation.canned_contexts">Proto's |
| Built-In Contexts</a></span></dt> |
| </dl></div> |
| <p> |
| Once you have constructed a Proto expression tree, either by using Proto's |
| operator overloads or with <code class="computeroutput"><a class="link" href="../boost/proto/make_expr_id1362445.html" title="Function make_expr">proto::make_expr()</a></code> |
| and friends, you probably want to actually <span class="emphasis"><em>do</em></span> something |
| with it. The simplest option is to use <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">()</span></code>, a generic expression evaluator. To use |
| <code class="computeroutput"><a class="link" href="../boost/proto/eval_id1354297.html" title="Function eval">proto::eval()</a></code>, you'll need to define |
| a <span class="emphasis"><em>context</em></span> that tells <code class="computeroutput"><a class="link" href="../boost/proto/eval_id1354297.html" title="Function eval">proto::eval()</a></code> |
| how each node should be evaluated. This section goes through the nuts and |
| bolts of using <code class="computeroutput"><a class="link" href="../boost/proto/eval_id1354297.html" title="Function eval">proto::eval()</a></code>, defining evaluation contexts, |
| and using the contexts that Proto provides. |
| </p> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">()</span></code> |
| is a less powerful but easier-to-use evaluation technique than Proto |
| transforms, which are covered later. Although very powerful, transforms |
| have a steep learning curve and can be more difficult to debug. <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">()</span></code> |
| is a rather weak tree traversal algorithm. Dan Marsden has been working |
| on a more general and powerful tree traversal library. When it is ready, |
| I anticipate that it will eliminate the need for <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">()</span></code>. |
| </p></td></tr> |
| </table></div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_evaluation.proto_eval"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_evaluation.proto_eval" title="Evaluating an Expression with proto::eval()">Evaluating |
| an Expression with <code class="literal">proto::eval()</code></a> |
| </h5></div></div></div> |
| <div class="blockquote"><blockquote class="blockquote"><p> |
| <span class="bold"><strong>Synopsis:</strong></span> |
| </p></blockquote></div> |
| <pre class="programlisting"><span class="keyword">namespace</span> <span class="identifier">proto</span> |
| <span class="special">{</span> |
| <span class="keyword">namespace</span> <span class="identifier">result_of</span> |
| <span class="special">{</span> |
| <span class="comment">// A metafunction for calculating the return</span> |
| <span class="comment">// type of proto::eval() given certain Expr</span> |
| <span class="comment">// and Context types.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Context</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> |
| <span class="keyword">typename</span> <span class="identifier">Context</span><span class="special">::</span><span class="keyword">template</span> <span class="identifier">eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="identifier">result_type</span> |
| <span class="identifier">type</span><span class="special">;</span> |
| <span class="special">};</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">namespace</span> <span class="identifier">functional</span> |
| <span class="special">{</span> |
| <span class="comment">// A callable function object type for evaluating</span> |
| <span class="comment">// a Proto expression with a certain context.</span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span> <span class="special">:</span> <span class="identifier">callable</span> |
| <span class="special">{</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Sig</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">result</span><span class="special">;</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Context</span><span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">Context</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">Expr</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">Context</span> <span class="special">&</span><span class="identifier">context</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Context</span><span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">Context</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">Expr</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">Context</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">context</span><span class="special">)</span> <span class="keyword">const</span><span class="special">;</span> |
| <span class="special">};</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Context</span><span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">Context</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="identifier">eval</span><span class="special">(</span><span class="identifier">Expr</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">Context</span> <span class="special">&</span><span class="identifier">context</span><span class="special">);</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Context</span><span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">Context</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="identifier">eval</span><span class="special">(</span><span class="identifier">Expr</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">Context</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">context</span><span class="special">);</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| Given an expression and an evaluation context, using <code class="computeroutput"><a class="link" href="../boost/proto/eval_id1354297.html" title="Function eval">proto::eval()</a></code> |
| is quite simple. Simply pass the expression and the context to <code class="computeroutput"><a class="link" href="../boost/proto/eval_id1354297.html" title="Function eval">proto::eval()</a></code> and it does the rest |
| and returns the result. You can use the <code class="computeroutput"><span class="identifier">eval</span><span class="special"><></span></code> metafunction in the <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span></code> namespace to compute the |
| return type of <code class="computeroutput"><a class="link" href="../boost/proto/eval_id1354297.html" title="Function eval">proto::eval()</a></code>. The following demonstrates |
| a use of <code class="computeroutput"><a class="link" href="../boost/proto/eval_id1354297.html" title="Function eval">proto::eval()</a></code>: |
| </p> |
| <pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">eval</span><span class="special"><</span><span class="identifier">Expr</span> <span class="keyword">const</span><span class="special">,</span> <span class="identifier">MyContext</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="identifier">MyEvaluate</span><span class="special">(</span><span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="comment">// Some user-defined context type</span> |
| <span class="identifier">MyContext</span> <span class="identifier">ctx</span><span class="special">;</span> |
| |
| <span class="comment">// Evaluate an expression with the context</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| What <code class="computeroutput"><a class="link" href="../boost/proto/eval_id1354297.html" title="Function eval">proto::eval()</a></code> does is also very simple. |
| It defers most of the work to the context itself. Here essentially is |
| the implementation of <code class="computeroutput"><a class="link" href="../boost/proto/eval_id1354297.html" title="Function eval">proto::eval()</a></code>: |
| </p> |
| <pre class="programlisting"><span class="comment">// eval() dispatches to a nested "eval<>" function</span> |
| <span class="comment">// object within the Context:</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Context</span><span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">Context</span><span class="special">::</span><span class="keyword">template</span> <span class="identifier">eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="identifier">result_type</span> |
| <span class="identifier">eval</span><span class="special">(</span><span class="identifier">Expr</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">Context</span> <span class="special">&</span><span class="identifier">ctx</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">typename</span> <span class="identifier">Context</span><span class="special">::</span><span class="keyword">template</span> <span class="identifier">eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">></span> <span class="identifier">eval_fun</span><span class="special">;</span> |
| <span class="keyword">return</span> <span class="identifier">eval_fun</span><span class="special">(</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| Really, <code class="computeroutput"><a class="link" href="../boost/proto/eval_id1354297.html" title="Function eval">proto::eval()</a></code> is nothing more than |
| a thin wrapper that dispatches to the appropriate handler within the |
| context class. In the next section, we'll see how to implement a context |
| class from scratch. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_evaluation.contexts"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_evaluation.contexts" title="Defining an Evaluation Context">Defining |
| an Evaluation Context</a> |
| </h5></div></div></div> |
| <p> |
| As we saw in the previous section, there is really not much to the <code class="computeroutput"><a class="link" href="../boost/proto/eval_id1354297.html" title="Function eval">proto::eval()</a></code> function. Rather, all |
| the interesting expression evaluation goes on within a context class. |
| This section shows how to implement one from scratch. |
| </p> |
| <p> |
| All context classes have roughly the following form: |
| </p> |
| <pre class="programlisting"><span class="comment">// A prototypical user-defined context.</span> |
| <span class="keyword">struct</span> <span class="identifier">MyContext</span> |
| <span class="special">{</span> |
| <span class="comment">// A nested eval<> class template</span> |
| <span class="keyword">template</span><span class="special"><</span> |
| <span class="keyword">typename</span> <span class="identifier">Expr</span> |
| <span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Tag</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag_of</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span><span class="special">;</span> |
| |
| <span class="comment">// Handle terminal nodes here...</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="comment">// Must have a nested result_type typedef.</span> |
| <span class="keyword">typedef</span> <span class="special">...</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="comment">// Must have a function call operator that takes</span> |
| <span class="comment">// an expression and the context.</span> |
| <span class="identifier">result_type</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">Expr</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">MyContext</span> <span class="special">&</span><span class="identifier">ctx</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="special">...;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// ... other specializations of struct eval<> ...</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| Context classes are nothing more than a collection of specializations |
| of a nested <code class="computeroutput"><span class="identifier">eval</span><span class="special"><></span></code> |
| class template. Each specialization handles a different expression type. |
| </p> |
| <p> |
| In the <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.hello_calculator" title="Hello Calculator">Hello |
| Calculator</a> section, we saw an example of a user-defined context |
| class for evaluating calculator expressions. That context class was implemented |
| with the help of Proto's <code class="computeroutput"><a class="link" href="../boost/proto/context/callable_context.html" title="Struct template callable_context">proto::callable_context<></a></code>. |
| If we were to implement it from scratch, it would look something like |
| this: |
| </p> |
| <pre class="programlisting"><span class="comment">// The calculator_context from the "Hello Calculator" section,</span> |
| <span class="comment">// implemented from scratch.</span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_context</span> |
| <span class="special">{</span> |
| <span class="comment">// The values with which we'll replace the placeholders</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span> <span class="identifier">args</span><span class="special">;</span> |
| |
| <span class="keyword">template</span><span class="special"><</span> |
| <span class="keyword">typename</span> <span class="identifier">Expr</span> |
| <span class="comment">// defaulted template parameters, so we can</span> |
| <span class="comment">// specialize on the expressions that need</span> |
| <span class="comment">// special handling.</span> |
| <span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Tag</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag_of</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Arg0</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="number">0</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span><span class="special">;</span> |
| |
| <span class="comment">// Handle placeholder terminals here...</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">I</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">,</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="identifier">I</span><span class="special">></span> <span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">double</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">result_type</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">Expr</span> <span class="special">&,</span> <span class="identifier">MyContext</span> <span class="special">&</span><span class="identifier">ctx</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">args</span><span class="special">[</span><span class="identifier">I</span><span class="special">];</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Handle other terminals here...</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Arg0</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">,</span> <span class="identifier">Arg0</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">double</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">result_type</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">Expr</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">MyContext</span> <span class="special">&)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">child</span><span class="special">(</span><span class="identifier">expr</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Handle addition here...</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Arg0</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">plus</span><span class="special">,</span> <span class="identifier">Arg0</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">double</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">result_type</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">Expr</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">MyContext</span> <span class="special">&</span><span class="identifier">ctx</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">left</span><span class="special">(</span><span class="identifier">expr</span><span class="special">),</span> <span class="identifier">ctx</span><span class="special">)</span> |
| <span class="special">+</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">right</span><span class="special">(</span><span class="identifier">expr</span><span class="special">),</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// ... other eval<> specializations for other node types ...</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| Now we can use <code class="computeroutput"><a class="link" href="../boost/proto/eval_id1354297.html" title="Function eval">proto::eval()</a></code> with the context class |
| above to evaluate calculator expressions as follows: |
| </p> |
| <pre class="programlisting"><span class="comment">// Evaluate an expression with a calculator_context</span> |
| <span class="identifier">calculator_context</span> <span class="identifier">ctx</span><span class="special">;</span> |
| <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">args</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">5</span><span class="special">);</span> |
| <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">args</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">6</span><span class="special">);</span> |
| <span class="keyword">double</span> <span class="identifier">d</span> <span class="special">=</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">_1</span> <span class="special">+</span> <span class="identifier">_2</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="identifier">assert</span><span class="special">(</span><span class="number">11</span> <span class="special">==</span> <span class="identifier">d</span><span class="special">);</span> |
| </pre> |
| <p> |
| Defining a context from scratch this way is tedious and verbose, but |
| it gives you complete control over how the expression is evaluated. The |
| context class in the <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.hello_calculator" title="Hello Calculator">Hello |
| Calculator</a> example was much simpler. In the next section we'll |
| see the helper class Proto provides to ease the job of implementing context |
| classes. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_evaluation.canned_contexts"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_evaluation.canned_contexts" title="Proto's Built-In Contexts">Proto's |
| Built-In Contexts</a> |
| </h5></div></div></div> |
| <p> |
| Proto provides some ready-made context classes that you can use as-is, |
| or that you can use to help while implementing your own contexts. They |
| are: |
| </p> |
| <div class="variablelist"> |
| <p class="title"><b></b></p> |
| <dl> |
| <dt><span class="term"><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_evaluation.canned_contexts.default_context" title="default_context"><code class="literal">default_context</code></a></span></dt> |
| <dd><p> |
| An evaluation context that assigns the usual C++ meanings to all |
| the operators. For example, addition nodes are handled by evaluating |
| the left and right children and then adding the results. The <code class="computeroutput"><a class="link" href="../boost/proto/context/default_context.html" title="Struct default_context">proto::default_context</a></code> |
| uses Boost.Typeof to deduce the types of the expressions it evaluates. |
| </p></dd> |
| <dt><span class="term"><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_evaluation.canned_contexts.null_context" title="null_context"><code class="literal">null_context</code></a></span></dt> |
| <dd><p> |
| A simple context that recursively evaluates children but does not |
| combine the results in any way and returns void. |
| </p></dd> |
| <dt><span class="term"><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_evaluation.canned_contexts.callable_context" title="callable_context<>"><code class="literal">callable_context<></code></a></span></dt> |
| <dd><p> |
| A helper that simplifies the job of writing context classes. Rather |
| than writing template specializations, with <code class="computeroutput"><a class="link" href="../boost/proto/context/callable_context.html" title="Struct template callable_context">proto::callable_context<></a></code> |
| you write a function object with an overloaded function call operator. |
| Any expressions not handled by an overload are automatically dispatched |
| to a default evaluation context that you can specify. |
| </p></dd> |
| </dl> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h6 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_evaluation.canned_contexts.default_context"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_evaluation.canned_contexts.default_context" title="default_context"><code class="literal">default_context</code></a> |
| </h6></div></div></div> |
| <p> |
| The <code class="computeroutput"><a class="link" href="../boost/proto/context/default_context.html" title="Struct default_context">proto::default_context</a></code> is an |
| evaluation context that assigns the usual C++ meanings to all the operators. |
| For example, addition nodes are handled by evaluating the left and |
| right children and then adding the results. The <code class="computeroutput"><a class="link" href="../boost/proto/context/default_context.html" title="Struct default_context">proto::default_context</a></code> uses |
| Boost.Typeof to deduce the types of the expressions it evaluates. |
| </p> |
| <p> |
| For example, consider the following "Hello World" example: |
| </p> |
| <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">proto</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">context</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">typeof</span><span class="special">/</span><span class="identifier">std</span><span class="special">/</span><span class="identifier">ostream</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">;</span> |
| |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span> <span class="special">>::</span><span class="identifier">type</span> <span class="identifier">cout_</span> <span class="special">=</span> <span class="special">{</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Expr</span> <span class="special">></span> |
| <span class="keyword">void</span> <span class="identifier">evaluate</span><span class="special">(</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">expr</span> <span class="special">)</span> |
| <span class="special">{</span> |
| <span class="comment">// Evaluate the expression with default_context,</span> |
| <span class="comment">// to give the operators their C++ meanings:</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">default_context</span> <span class="identifier">ctx</span><span class="special">;</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="identifier">evaluate</span><span class="special">(</span> <span class="identifier">cout_</span> <span class="special"><<</span> <span class="string">"hello"</span> <span class="special"><<</span> <span class="char">','</span> <span class="special"><<</span> <span class="string">" world"</span> <span class="special">);</span> |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| This program outputs the following: |
| </p> |
| <pre class="programlisting">hello, world |
| </pre> |
| <p> |
| <code class="computeroutput"><a class="link" href="../boost/proto/context/default_context.html" title="Struct default_context">proto::default_context</a></code> is trivially |
| defined in terms of a <code class="computeroutput"><span class="identifier">default_eval</span><span class="special"><></span></code> template, as follows: |
| </p> |
| <pre class="programlisting"><span class="comment">// Definition of default_context</span> |
| <span class="keyword">struct</span> <span class="identifier">default_context</span> |
| <span class="special">{</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span> |
| <span class="special">:</span> <span class="identifier">default_eval</span><span class="special"><</span> |
| <span class="identifier">Expr</span> |
| <span class="special">,</span> <span class="identifier">default_context</span> <span class="keyword">const</span> |
| <span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">tag_of</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| There are a bunch of <code class="computeroutput"><span class="identifier">default_eval</span><span class="special"><></span></code> specializations, each of which |
| handles a different C++ operator. Here, for instance, is the specialization |
| for binary addition: |
| </p> |
| <pre class="programlisting"><span class="comment">// A default expression evaluator for binary addition</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Context</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">default_eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">Context</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">plus</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">private</span><span class="special">:</span> |
| <span class="keyword">static</span> <span class="identifier">Expr</span> <span class="special">&</span> <span class="identifier">s_expr</span><span class="special">;</span> |
| <span class="keyword">static</span> <span class="identifier">Context</span> <span class="special">&</span> <span class="identifier">s_ctx</span><span class="special">;</span> |
| |
| <span class="keyword">public</span><span class="special">:</span> |
| <span class="keyword">typedef</span> |
| <span class="identifier">decltype</span><span class="special">(</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="number">0</span><span class="special">>(</span><span class="identifier">s_expr</span><span class="special">),</span> <span class="identifier">s_ctx</span><span class="special">)</span> |
| <span class="special">+</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="number">1</span><span class="special">>(</span><span class="identifier">s_expr</span><span class="special">),</span> <span class="identifier">s_ctx</span><span class="special">)</span> |
| <span class="special">)</span> |
| <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">result_type</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">Expr</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">Context</span> <span class="special">&</span><span class="identifier">ctx</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="number">0</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">),</span> <span class="identifier">ctx</span><span class="special">)</span> |
| <span class="special">+</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="number">1</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">),</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| The above code uses <code class="computeroutput"><span class="identifier">decltype</span></code> |
| to calculate the return type of the function call operator. <code class="computeroutput"><span class="identifier">decltype</span></code> is a new keyword in the |
| next version of C++ that gets the type of any expression. Most compilers |
| do not yet support <code class="computeroutput"><span class="identifier">decltype</span></code> |
| directly, so <code class="computeroutput"><span class="identifier">default_eval</span><span class="special"><></span></code> uses the Boost.Typeof library |
| to emulate it. On some compilers, that may mean that <code class="computeroutput"><span class="identifier">default_context</span></code> either doesn't work |
| or that it requires you to register your types with the Boost.Typeof |
| library. Check the documentation for Boost.Typeof to see. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h6 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_evaluation.canned_contexts.null_context"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_evaluation.canned_contexts.null_context" title="null_context"><code class="literal">null_context</code></a> |
| </h6></div></div></div> |
| <p> |
| The <code class="computeroutput"><a class="link" href="../boost/proto/context/null_context.html" title="Struct null_context">proto::null_context<></a></code> |
| is a simple context that recursively evaluates children but does not |
| combine the results in any way and returns void. It is useful in conjunction |
| with <code class="computeroutput"><span class="identifier">callable_context</span><span class="special"><></span></code>, or when defining your own |
| contexts which mutate an expression tree in-place rather than accumulate |
| a result, as we'll see below. |
| </p> |
| <p> |
| <code class="computeroutput"><a class="link" href="../boost/proto/context/null_context.html" title="Struct null_context">proto::null_context<></a></code> |
| is trivially implemented in terms of <code class="computeroutput"><span class="identifier">null_eval</span><span class="special"><></span></code> as follows: |
| </p> |
| <pre class="programlisting"><span class="comment">// Definition of null_context</span> |
| <span class="keyword">struct</span> <span class="identifier">null_context</span> |
| <span class="special">{</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span> |
| <span class="special">:</span> <span class="identifier">null_eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">null_context</span> <span class="keyword">const</span><span class="special">,</span> <span class="identifier">Expr</span><span class="special">::</span><span class="identifier">proto_arity</span><span class="special">::</span><span class="identifier">value</span><span class="special">></span> |
| <span class="special">{};</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| And <code class="computeroutput"><span class="identifier">null_eval</span><span class="special"><></span></code> |
| is also trivially implemented. Here, for instance is a binary <code class="computeroutput"><span class="identifier">null_eval</span><span class="special"><></span></code>: |
| </p> |
| <pre class="programlisting"><span class="comment">// Binary null_eval<></span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Context</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">null_eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">Context</span><span class="special">,</span> <span class="number">2</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">void</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">Expr</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">Context</span> <span class="special">&</span><span class="identifier">ctx</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="number">0</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">),</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="number">1</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">),</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| When would such classes be useful? Imagine you have an expression tree |
| with integer terminals, and you would like to increment each integer |
| in-place. You might define an evaluation context as follows: |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">increment_ints</span> |
| <span class="special">{</span> |
| <span class="comment">// By default, just evaluate all children by delegating</span> |
| <span class="comment">// to the null_eval<></span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Arg</span> <span class="special">=</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">child</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="identifier">type</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span> |
| <span class="special">:</span> <span class="identifier">null_eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">increment_ints</span> <span class="keyword">const</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Increment integer terminals</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">int</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">void</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">Expr</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">increment_ints</span> <span class="keyword">const</span> <span class="special">&)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="special">++</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">child</span><span class="special">(</span><span class="identifier">expr</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| In the next section on <code class="computeroutput"><a class="link" href="../boost/proto/context/callable_context.html" title="Struct template callable_context">proto::callable_context<></a></code>, |
| we'll see an even simpler way to achieve the same thing. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h6 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_evaluation.canned_contexts.callable_context"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_evaluation.canned_contexts.callable_context" title="callable_context<>"><code class="literal">callable_context<></code></a> |
| </h6></div></div></div> |
| <p> |
| The <code class="computeroutput"><a class="link" href="../boost/proto/context/callable_context.html" title="Struct template callable_context">proto::callable_context<></a></code> |
| is a helper that simplifies the job of writing context classes. Rather |
| than writing template specializations, with <code class="computeroutput"><a class="link" href="../boost/proto/context/callable_context.html" title="Struct template callable_context">proto::callable_context<></a></code> |
| you write a function object with an overloaded function call operator. |
| Any expressions not handled by an overload are automatically dispatched |
| to a default evaluation context that you can specify. |
| </p> |
| <p> |
| Rather than an evaluation context in its own right, <code class="computeroutput"><a class="link" href="../boost/proto/context/callable_context.html" title="Struct template callable_context">proto::callable_context<></a></code> |
| is more properly thought of as a context adaptor. To use it, you must |
| define your own context that inherits from <code class="computeroutput"><a class="link" href="../boost/proto/context/callable_context.html" title="Struct template callable_context">proto::callable_context<></a></code>. |
| </p> |
| <p> |
| In the <a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_evaluation.canned_contexts.null_context" title="null_context"><code class="literal">null_context</code></a> |
| section, we saw how to implement an evaluation context that increments |
| all the integers within an expression tree. Here is how to do the same |
| thing with the <code class="computeroutput"><a class="link" href="../boost/proto/context/callable_context.html" title="Struct template callable_context">proto::callable_context<></a></code>: |
| </p> |
| <pre class="programlisting"><span class="comment">// An evaluation context that increments all</span> |
| <span class="comment">// integer terminals in-place.</span> |
| <span class="keyword">struct</span> <span class="identifier">increment_ints</span> |
| <span class="special">:</span> <span class="identifier">callable_context</span><span class="special"><</span> |
| <span class="identifier">increment_ints</span> <span class="keyword">const</span> <span class="comment">// derived context</span> |
| <span class="special">,</span> <span class="identifier">null_context</span> <span class="keyword">const</span> <span class="comment">// fall-back context</span> |
| <span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">void</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="comment">// Handle int terminals here:</span> |
| <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">,</span> <span class="keyword">int</span> <span class="special">&</span><span class="identifier">i</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="special">++</span><span class="identifier">i</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| With such a context, we can do the following: |
| </p> |
| <pre class="programlisting"><span class="identifier">literal</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">,</span> <span class="identifier">j</span> <span class="special">=</span> <span class="number">10</span><span class="special">;</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span> <span class="identifier">i</span> <span class="special">-</span> <span class="identifier">j</span> <span class="special">*</span> <span class="number">3.14</span><span class="special">,</span> <span class="identifier">increment_ints</span><span class="special">()</span> <span class="special">);</span> |
| |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"i = "</span> <span class="special"><<</span> <span class="identifier">i</span><span class="special">.</span><span class="identifier">get</span><span class="special">()</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"j = "</span> <span class="special"><<</span> <span class="identifier">j</span><span class="special">.</span><span class="identifier">get</span><span class="special">()</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| </pre> |
| <p> |
| This program outputs the following, which shows that the integers |
| <code class="computeroutput"><span class="identifier">i</span></code> and <code class="computeroutput"><span class="identifier">j</span></code> have been incremented by <code class="computeroutput"><span class="number">1</span></code>: |
| </p> |
| <pre class="programlisting">i = 1 |
| j = 11 |
| </pre> |
| <p> |
| In the <code class="computeroutput"><span class="identifier">increment_ints</span></code> |
| context, we didn't have to define any nested <code class="computeroutput"><span class="identifier">eval</span><span class="special"><></span></code> templates. That's because |
| <code class="computeroutput"><a class="link" href="../boost/proto/context/callable_context.html" title="Struct template callable_context">proto::callable_context<></a></code> |
| implements them for us. <code class="computeroutput"><a class="link" href="../boost/proto/context/callable_context.html" title="Struct template callable_context">proto::callable_context<></a></code> |
| takes two template parameters: the derived context and a fall-back |
| context. For each node in the expression tree being evaluated, <code class="computeroutput"><a class="link" href="../boost/proto/context/callable_context.html" title="Struct template callable_context">proto::callable_context<></a></code> checks to see if |
| there is an overloaded <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code> in the derived context that accepts |
| it. Given some expression <code class="computeroutput"><span class="identifier">expr</span></code> |
| of type <code class="computeroutput"><span class="identifier">Expr</span></code>, and a |
| context <code class="computeroutput"><span class="identifier">ctx</span></code>, it attempts |
| to call: |
| </p> |
| <pre class="programlisting"><span class="identifier">ctx</span><span class="special">(</span> |
| <span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">::</span><span class="identifier">proto_tag</span><span class="special">()</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="number">0</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="number">1</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">...</span> |
| <span class="special">);</span> |
| </pre> |
| <p> |
| Using function overloading and metaprogramming tricks, <code class="computeroutput"><a class="link" href="../boost/proto/context/callable_context.html" title="Struct template callable_context">proto::callable_context<></a></code> |
| can detect at compile-time whether such a function exists or not. If |
| so, that function is called. If not, the current expression is passed |
| to the fall-back evaluation context to be processed. |
| </p> |
| <p> |
| We saw another example of the <code class="computeroutput"><a class="link" href="../boost/proto/context/callable_context.html" title="Struct template callable_context">proto::callable_context<></a></code> |
| when we looked at the simple calculator expression evaluator. There, |
| we wanted to customize the evaluation of placeholder terminals, and |
| delegate the handling of all other nodes to the <code class="computeroutput"><a class="link" href="../boost/proto/context/default_context.html" title="Struct default_context">proto::default_context</a></code>. We did |
| that as follows: |
| </p> |
| <pre class="programlisting"><span class="comment">// An evaluation context for calculator expressions that</span> |
| <span class="comment">// explicitly handles placeholder terminals, but defers the</span> |
| <span class="comment">// processing of all other nodes to the default_context.</span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_context</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable_context</span><span class="special"><</span> <span class="identifier">calculator_context</span> <span class="keyword">const</span> <span class="special">></span> |
| <span class="special">{</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span> <span class="identifier">args</span><span class="special">;</span> |
| |
| <span class="comment">// Define the result type of the calculator.</span> |
| <span class="keyword">typedef</span> <span class="keyword">double</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="comment">// Handle the placeholders:</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">I</span><span class="special">></span> |
| <span class="keyword">double</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">,</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="identifier">I</span><span class="special">>)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="keyword">this</span><span class="special">-></span><span class="identifier">args</span><span class="special">[</span><span class="identifier">I</span><span class="special">];</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| In this case, we didn't specify a fall-back context. In that case, |
| <code class="computeroutput"><a class="link" href="../boost/proto/context/callable_context.html" title="Struct template callable_context">proto::callable_context<></a></code> |
| uses the <code class="computeroutput"><a class="link" href="../boost/proto/context/default_context.html" title="Struct default_context">proto::default_context</a></code>. With |
| the above <code class="computeroutput"><span class="identifier">calculator_context</span></code> |
| and a couple of appropriately defined placeholder terminals, we can |
| evaluate calculator expressions, as demonstrated below: |
| </p> |
| <pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">I</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">placeholder</span> |
| <span class="special">{};</span> |
| |
| <span class="identifier">terminal</span><span class="special"><</span><span class="identifier">placeholder</span><span class="special"><</span><span class="number">0</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">_1</span> <span class="special">=</span> <span class="special">{{}};</span> |
| <span class="identifier">terminal</span><span class="special"><</span><span class="identifier">placeholder</span><span class="special"><</span><span class="number">1</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">_2</span> <span class="special">=</span> <span class="special">{{}};</span> |
| <span class="comment">// ...</span> |
| |
| <span class="identifier">calculator_context</span> <span class="identifier">ctx</span><span class="special">;</span> |
| <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">args</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">4</span><span class="special">);</span> |
| <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">args</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">5</span><span class="special">);</span> |
| |
| <span class="keyword">double</span> <span class="identifier">j</span> <span class="special">=</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span> <span class="special">(</span><span class="identifier">_2</span> <span class="special">-</span> <span class="identifier">_1</span><span class="special">)</span> <span class="special">/</span> <span class="identifier">_2</span> <span class="special">*</span> <span class="number">100</span><span class="special">,</span> <span class="identifier">ctx</span> <span class="special">);</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"j = "</span> <span class="special"><<</span> <span class="identifier">j</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| </pre> |
| <p> |
| The above code displays the following: |
| </p> |
| <pre class="programlisting">j = 20 |
| </pre> |
| </div> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_transformation"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation" title="Expression Transformation: Semantic Actions">Expression |
| Transformation: Semantic Actions</a> |
| </h4></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.__activating__your_grammars"><span class="quote">“<span class="quote">Activating</span>”</span> |
| Your Grammars</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.handling_alternation_and_recursion">Handling |
| Alternation and Recursion</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.callable_transforms">Callable |
| Transforms</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.object_transforms">Object |
| Transforms</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.example__calculator_arity">Example: |
| Calculator Arity</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.state">Transforms |
| With State Accumulation</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.data">Passing |
| Auxiliary Data to Transforms</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.canned_transforms">Proto's |
| Built-In Transforms</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.primitives">Building |
| Custom Primitive Transforms</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.is_callable">Making |
| Your Transform Callable</a></span></dt> |
| </dl></div> |
| <p> |
| If you have ever built a parser with the help of a tool like Antlr, yacc |
| or Boost.Spirit, you might be familiar with <span class="emphasis"><em>semantic actions</em></span>. |
| In addition to allowing you to define the grammar of the language recognized |
| by the parser, these tools let you embed code within your grammar that |
| executes when parts of the grammar participate in a parse. Proto has the |
| equivalent of semantic actions. They are called <span class="emphasis"><em>transforms</em></span>. |
| This section describes how to embed transforms within your Proto grammars, |
| turning your grammars into function objects that can manipulate or evaluate |
| expressions in powerful ways. |
| </p> |
| <p> |
| Proto transforms are an advanced topic. We'll take it slow, using examples |
| to illustrate the key concepts, starting simple. |
| </p> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_transformation.__activating__your_grammars"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.__activating__your_grammars" title="“Activating” Your Grammars"><span class="quote">“<span class="quote">Activating</span>”</span> |
| Your Grammars</a> |
| </h5></div></div></div> |
| <p> |
| The Proto grammars we've seen so far are static. You can check at compile-time |
| to see if an expression type matches a grammar, but that's it. Things |
| get more interesting when you give them runtime behaviors. A grammar |
| with embedded transforms is more than just a static grammar. It is a |
| function object that accepts expressions that match the grammar and does |
| <span class="emphasis"><em>something</em></span> with them. |
| </p> |
| <p> |
| Below is a very simple grammar. It matches terminal expressions. |
| </p> |
| <pre class="programlisting"><span class="comment">// A simple Proto grammar that matches all terminals</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">_</span> <span class="special">></span> |
| </pre> |
| <p> |
| Here is the same grammar with a transform that extracts the value from |
| the terminal: |
| </p> |
| <pre class="programlisting"><span class="comment">// A simple Proto grammar that matches all terminals</span> |
| <span class="comment">// *and* a function object that extracts the value from</span> |
| <span class="comment">// the terminal</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">_</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span> <span class="comment">// <-- Look, a transform!</span> |
| <span class="special">></span> |
| </pre> |
| <p> |
| You can read this as follows: when you match a terminal expression, extract |
| the value. The type <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span></code> |
| is a so-called transform. Later we'll see what makes it a transform, |
| but for now just think of it as a kind of function object. Note the use |
| of <code class="computeroutput"><a class="link" href="../boost/proto/when.html" title="Struct template when">proto::when<></a></code>: the first template |
| parameter is the grammar to match and the second is the transform to |
| execute. The result is both a grammar that matches terminal expressions |
| and a function object that accepts terminal expressions and extracts |
| their values. |
| </p> |
| <p> |
| As with ordinary grammars, we can define an empty struct that inherits |
| from a grammar+transform to give us an easy way to refer back to the |
| thing we're defining, as follows: |
| </p> |
| <pre class="programlisting"><span class="comment">// A grammar and a function object, as before</span> |
| <span class="keyword">struct</span> <span class="identifier">Value</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">_</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// "Value" is a grammar that matches terminal expressions</span> |
| <span class="identifier">BOOST_MPL_ASSERT</span><span class="special">((</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">>::</span><span class="identifier">type</span><span class="special">,</span> <span class="identifier">Value</span> <span class="special">></span> <span class="special">));</span> |
| |
| <span class="comment">// "Value" also defines a function object that accepts terminals</span> |
| <span class="comment">// and extracts their value.</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">>::</span><span class="identifier">type</span> <span class="identifier">answer</span> <span class="special">=</span> <span class="special">{</span><span class="number">42</span><span class="special">};</span> |
| <span class="identifier">Value</span> <span class="identifier">get_value</span><span class="special">;</span> |
| <span class="keyword">int</span> <span class="identifier">i</span> <span class="special">=</span> <span class="identifier">get_value</span><span class="special">(</span> <span class="identifier">answer</span> <span class="special">);</span> |
| </pre> |
| <p> |
| As already mentioned, <code class="computeroutput"><span class="identifier">Value</span></code> |
| is a grammar that matches terminal expressions and a function object |
| that operates on terminal expressions. It would be an error to pass a |
| non-terminal expression to the <code class="computeroutput"><span class="identifier">Value</span></code> |
| function object. This is a general property of grammars with transforms; |
| when using them as function objects, expressions passed to them must |
| match the grammar. |
| </p> |
| <p> |
| Proto grammars are valid TR1-style function objects. That means you can |
| use <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">result_of</span><span class="special"><></span></code> |
| to ask a grammar what its return type will be, given a particular expression |
| type. For instance, we can access the <code class="computeroutput"><span class="identifier">Value</span></code> |
| grammar's return type as follows: |
| </p> |
| <pre class="programlisting"><span class="comment">// We can use boost::result_of<> to get the return type</span> |
| <span class="comment">// of a Proto grammar.</span> |
| <span class="keyword">typedef</span> |
| <span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">result_of</span><span class="special"><</span><span class="identifier">Value</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">>::</span><span class="identifier">type</span><span class="special">)>::</span><span class="identifier">type</span> |
| <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="comment">// Check that we got the type we expected</span> |
| <span class="identifier">BOOST_MPL_ASSERT</span><span class="special">((</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">is_same</span><span class="special"><</span><span class="identifier">result_type</span><span class="special">,</span> <span class="keyword">int</span><span class="special">></span> <span class="special">));</span> |
| </pre> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| A grammar with embedded transforms is both a grammar and a function |
| object. Calling these things "grammars with transforms" would |
| get tedious. We could call them something like "active grammars", |
| but as we'll see <span class="emphasis"><em>every</em></span> grammar that you can define |
| with Proto is "active"; that is, every grammar has some behavior |
| when used as a function object. So we'll continue calling these things |
| plain "grammars". The term "transform" is reserved |
| for the thing that is used as the second parameter to the <code class="computeroutput"><a class="link" href="../boost/proto/when.html" title="Struct template when">proto::when<></a></code> template. |
| </p></td></tr> |
| </table></div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_transformation.handling_alternation_and_recursion"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.handling_alternation_and_recursion" title="Handling Alternation and Recursion">Handling |
| Alternation and Recursion</a> |
| </h5></div></div></div> |
| <p> |
| Most grammars are a little more complicated than the one in the preceding |
| section. For the sake of illustration, let's define a rather nonsensical |
| grammar that matches any expression and recurses to the leftmost terminal |
| and returns its value. It will demonstrate how two key concepts of Proto |
| grammars -- alternation and recursion -- interact with transforms. The |
| grammar is described below. |
| </p> |
| <pre class="programlisting"><span class="comment">// A grammar that matches any expression, and a function object</span> |
| <span class="comment">// that returns the value of the leftmost terminal.</span> |
| <span class="keyword">struct</span> <span class="identifier">LeftmostLeaf</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="comment">// If the expression is a terminal, return its value</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">_</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span> |
| <span class="special">></span> |
| <span class="comment">// Otherwise, it is a non-terminal. Return the result</span> |
| <span class="comment">// of invoking LeftmostLeaf on the 0th (leftmost) child.</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">_</span> |
| <span class="special">,</span> <span class="identifier">LeftmostLeaf</span><span class="special">(</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child0</span> <span class="special">)</span> |
| <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// A Proto terminal wrapping std::cout</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span> <span class="special">>::</span><span class="identifier">type</span> <span class="identifier">cout_</span> <span class="special">=</span> <span class="special">{</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">};</span> |
| |
| <span class="comment">// Create an expression and use LeftmostLeaf to extract the</span> |
| <span class="comment">// value of the leftmost terminal, which will be std::cout.</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span> <span class="identifier">sout</span> <span class="special">=</span> <span class="identifier">LeftmostLeaf</span><span class="special">()(</span> <span class="identifier">cout_</span> <span class="special"><<</span> <span class="string">"the answer: "</span> <span class="special"><<</span> <span class="number">42</span> <span class="special"><<</span> <span class="char">'\n'</span> <span class="special">);</span> |
| </pre> |
| <p> |
| We've seen <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><></span></code> |
| before. Here it is serving two roles. First, it is a grammar that matches |
| any of its alternate sub-grammars; in this case, either a terminal or |
| a non-terminal. Second, it is also a function object that accepts an |
| expression, finds the alternate sub-grammar that matches the expression, |
| and applies its transform. And since <code class="computeroutput"><span class="identifier">LeftmostLeaf</span></code> |
| inherits from <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><></span></code>, |
| <code class="computeroutput"><span class="identifier">LeftmostLeaf</span></code> is also |
| both a grammar and a function object. |
| </p> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| The second alternate uses <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span></code> |
| as its grammar. Recall that <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span></code> |
| is the wildcard grammar that matches any expression. Since alternates |
| in <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><></span></code> |
| are tried in order, and since the first alternate handles all terminals, |
| the second alternate handles all (and only) non-terminals. Often enough, |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">_</span><span class="special">,</span> |
| <em class="replaceable"><code>some-transform</code></em> <span class="special">></span></code> |
| is the last alternate in a grammar, so for improved readability, you |
| could use the equivalent <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">otherwise</span><span class="special"><</span> <em class="replaceable"><code>some-transform</code></em> |
| <span class="special">></span></code>. |
| </p></td></tr> |
| </table></div> |
| <p> |
| The next section describes this grammar further. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_transformation.callable_transforms"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.callable_transforms" title="Callable Transforms">Callable |
| Transforms</a> |
| </h5></div></div></div> |
| <p> |
| In the grammar defined in the preceding section, the transform associated |
| with non-terminals is a little strange-looking: |
| </p> |
| <pre class="programlisting"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">_</span> |
| <span class="special">,</span> <span class="bold"><strong>LeftmostLeaf( proto::_child0 )</strong></span> <span class="comment">// <-- a "callable" transform</span> |
| <span class="special">></span> |
| </pre> |
| <p> |
| It has the effect of accepting non-terminal expressions, taking the 0th |
| (leftmost) child and recursively invoking the <code class="computeroutput"><span class="identifier">LeftmostLeaf</span></code> |
| function on it. But <code class="computeroutput"><span class="identifier">LeftmostLeaf</span><span class="special">(</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child0</span> |
| <span class="special">)</span></code> is actually a <span class="emphasis"><em>function |
| type</em></span>. Literally, it is the type of a function that accepts |
| an object of type <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child0</span></code> |
| and returns an object of type <code class="computeroutput"><span class="identifier">LeftmostLeaf</span></code>. |
| So how do we make sense of this transform? Clearly, there is no function |
| that actually has this signature, nor would such a function be useful. |
| The key is in understanding how <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><></span></code> <span class="emphasis"><em>interprets</em></span> |
| its second template parameter. |
| </p> |
| <p> |
| When the second template parameter to <code class="computeroutput"><a class="link" href="../boost/proto/when.html" title="Struct template when">proto::when<></a></code> |
| is a function type, <code class="computeroutput"><a class="link" href="../boost/proto/when.html" title="Struct template when">proto::when<></a></code> |
| interprets the function type as a transform. In this case, <code class="computeroutput"><span class="identifier">LeftmostLeaf</span></code> is treated as the type |
| of a function object to invoke, and <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child0</span></code> |
| is treated as a transform. First, <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child0</span></code> |
| is applied to the current expression (the non-terminal that matched this |
| alternate sub-grammar), and the result (the 0th child) is passed as an |
| argument to <code class="computeroutput"><span class="identifier">LeftmostLeaf</span></code>. |
| </p> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"> |
| <p> |
| <span class="bold"><strong>Transforms are a Domain-Specific Language</strong></span> |
| </p> |
| <p> |
| <code class="computeroutput"><span class="identifier">LeftmostLeaf</span><span class="special">(</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child0</span> <span class="special">)</span></code> |
| <span class="emphasis"><em>looks</em></span> like an invocation of the <code class="computeroutput"><span class="identifier">LeftmostLeaf</span></code> function object, but |
| it's not, but then it actually is! Why this confusing subterfuge? Function |
| types give us a natural and concise syntax for composing more complicated |
| transforms from simpler ones. The fact that the syntax is suggestive |
| of a function invocation is on purpose. It is a domain-specific embedded |
| language for defining expression transformations. If the subterfuge |
| worked, it may have fooled you into thinking the transform is doing |
| exactly what it actually does! And that's the point. |
| </p> |
| </td></tr> |
| </table></div> |
| <p> |
| The type <code class="computeroutput"><span class="identifier">LeftmostLeaf</span><span class="special">(</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child0</span> |
| <span class="special">)</span></code> is an example of a <span class="emphasis"><em>callable |
| transform</em></span>. It is a function type that represents a function |
| object to call and its arguments. The types <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child0</span></code> |
| and <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span></code> are <span class="emphasis"><em>primitive transforms</em></span>. |
| They are plain structs, not unlike function objects, from which callable |
| transforms can be composed. There is one other type of transform, <span class="emphasis"><em>object |
| transforms</em></span>, that we'll encounter next. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_transformation.object_transforms"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.object_transforms" title="Object Transforms">Object |
| Transforms</a> |
| </h5></div></div></div> |
| <p> |
| The very first transform we looked at simply extracted the value of terminals. |
| Let's do the same thing, but this time we'll promote all ints to longs |
| first. (Please forgive the contrived-ness of the examples so far; they |
| get more interesting later.) Here's the grammar: |
| </p> |
| <pre class="programlisting"><span class="comment">// A simple Proto grammar that matches all terminals,</span> |
| <span class="comment">// and a function object that extracts the value from</span> |
| <span class="comment">// the terminal, promoting ints to longs:</span> |
| <span class="keyword">struct</span> <span class="identifier">ValueWithPomote</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="keyword">int</span> <span class="special">></span> |
| <span class="special">,</span> <span class="keyword">long</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">)</span> <span class="comment">// <-- an "object" transform</span> |
| <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">_</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span> |
| <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| You can read the above grammar as follows: when you match an int terminal, |
| extract the value from the terminal and use it to initialize a long; |
| otherwise, when you match another kind of terminal, just extract the |
| value. The type <code class="computeroutput"><span class="keyword">long</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">)</span></code> |
| is a so-called <span class="emphasis"><em>object</em></span> transform. It looks like the |
| creation of a temporary long, but it's really a function type. Just as |
| a callable transform is a function type that represents a function to |
| call and its arguments, an object transforms is a function type that |
| represents an object to construct and the arguments to its constructor. |
| </p> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"> |
| <p> |
| <span class="bold"><strong>Object Transforms vs. Callable Transforms</strong></span> |
| </p> |
| <p> |
| When using function types as Proto transforms, they can either represent |
| an object to construct or a function to call. It is similar to "normal" |
| C++ where the syntax <code class="computeroutput"><span class="identifier">foo</span><span class="special">(</span><span class="string">"arg"</span><span class="special">)</span></code> can either be interpreted as an object |
| to construct or a function to call, depending on whether <code class="computeroutput"><span class="identifier">foo</span></code> is a type or a function. But |
| consider two of the transforms we've seen so far: |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="identifier">LeftmostLeaf</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child0</span><span class="special">)</span> <span class="comment">// <-- a callable transform</span> |
| <span class="keyword">long</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">)</span> <span class="comment">// <-- an object transform</span> |
| </pre> |
| <p> |
| </p> |
| <p> |
| Proto can't know in general which is which, so it uses a trait, <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">is_callable</span><span class="special"><></span></code>, |
| to differentiate. <code class="computeroutput"><span class="identifier">is_callable</span><span class="special"><</span> <span class="keyword">long</span> |
| <span class="special">>::</span><span class="identifier">value</span></code> |
| is false so <code class="computeroutput"><span class="keyword">long</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">)</span></code> |
| is an object to construct, but <code class="computeroutput"><span class="identifier">is_callable</span><span class="special"><</span> <span class="identifier">LeftmostLeaf</span> |
| <span class="special">>::</span><span class="identifier">value</span></code> |
| is true so <code class="computeroutput"><span class="identifier">LeftmostLeaf</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child0</span><span class="special">)</span></code> is a function to call. Later on, we'll |
| see how Proto recognizes a type as "callable". |
| </p> |
| </td></tr> |
| </table></div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_transformation.example__calculator_arity"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.example__calculator_arity" title="Example: Calculator Arity">Example: |
| Calculator Arity</a> |
| </h5></div></div></div> |
| <p> |
| Now that we have the basics of Proto transforms down, let's consider |
| a slightly more realistic example. We can use transforms to improve the |
| type-safety of the <a class="link" href="users_guide.html#boost_proto.users_guide.getting_started.hello_calculator" title="Hello Calculator">calculator |
| DSEL</a>. If you recall, it lets you write infix arithmetic expressions |
| involving argument placeholders like <code class="computeroutput"><span class="identifier">_1</span></code> |
| and <code class="computeroutput"><span class="identifier">_2</span></code> and pass them |
| to STL algorithms as function objects, as follows: |
| </p> |
| <pre class="programlisting"><span class="keyword">double</span> <span class="identifier">a1</span><span class="special">[</span><span class="number">4</span><span class="special">]</span> <span class="special">=</span> <span class="special">{</span> <span class="number">56</span><span class="special">,</span> <span class="number">84</span><span class="special">,</span> <span class="number">37</span><span class="special">,</span> <span class="number">69</span> <span class="special">};</span> |
| <span class="keyword">double</span> <span class="identifier">a2</span><span class="special">[</span><span class="number">4</span><span class="special">]</span> <span class="special">=</span> <span class="special">{</span> <span class="number">65</span><span class="special">,</span> <span class="number">120</span><span class="special">,</span> <span class="number">60</span><span class="special">,</span> <span class="number">70</span> <span class="special">};</span> |
| <span class="keyword">double</span> <span class="identifier">a3</span><span class="special">[</span><span class="number">4</span><span class="special">]</span> <span class="special">=</span> <span class="special">{</span> <span class="number">0</span> <span class="special">};</span> |
| |
| <span class="comment">// Use std::transform() and a calculator expression</span> |
| <span class="comment">// to calculate percentages given two input sequences:</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">transform</span><span class="special">(</span><span class="identifier">a1</span><span class="special">,</span> <span class="identifier">a1</span><span class="special">+</span><span class="number">4</span><span class="special">,</span> <span class="identifier">a2</span><span class="special">,</span> <span class="identifier">a3</span><span class="special">,</span> <span class="special">(</span><span class="identifier">_2</span> <span class="special">-</span> <span class="identifier">_1</span><span class="special">)</span> <span class="special">/</span> <span class="identifier">_2</span> <span class="special">*</span> <span class="number">100</span><span class="special">);</span> |
| </pre> |
| <p> |
| This works because we gave calculator expressions an <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code> that evaluates the expression, replacing |
| the placeholders with the arguments to <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code>. The overloaded <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><>::</span><span class="keyword">operator</span><span class="special">()</span></code> looked like this: |
| </p> |
| <pre class="programlisting"><span class="comment">// Overload operator() to invoke proto::eval() with</span> |
| <span class="comment">// our calculator_context.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">double</span> |
| <span class="identifier">calculator</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="keyword">operator</span><span class="special">()(</span><span class="keyword">double</span> <span class="identifier">a1</span> <span class="special">=</span> <span class="number">0</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">a2</span> <span class="special">=</span> <span class="number">0</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">calculator_context</span> <span class="identifier">ctx</span><span class="special">;</span> |
| <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">args</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">a1</span><span class="special">);</span> |
| <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">args</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">a2</span><span class="special">);</span> |
| |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| Although this works, it's not ideal because it doesn't warn users if |
| they supply too many or too few arguments to a calculator expression. |
| Consider the following mistakes: |
| </p> |
| <pre class="programlisting"><span class="special">(</span><span class="identifier">_1</span> <span class="special">*</span> <span class="identifier">_1</span><span class="special">)(</span><span class="number">4</span><span class="special">,</span> <span class="number">2</span><span class="special">);</span> <span class="comment">// Oops, too many arguments!</span> |
| <span class="special">(</span><span class="identifier">_2</span> <span class="special">*</span> <span class="identifier">_2</span><span class="special">)(</span><span class="number">42</span><span class="special">);</span> <span class="comment">// Oops, too few arguments!</span> |
| </pre> |
| <p> |
| The expression <code class="computeroutput"><span class="identifier">_1</span> <span class="special">*</span> |
| <span class="identifier">_1</span></code> defines a unary calculator |
| expression; it takes one argument and squares it. If we pass more than |
| one argument, the extra arguments will be silently ignored, which might |
| be surprising to users. The next expression, <code class="computeroutput"><span class="identifier">_2</span> |
| <span class="special">*</span> <span class="identifier">_2</span></code> |
| defines a binary calculator expression; it takes two arguments, ignores |
| the first and squares the second. If we only pass one argument, the code |
| silently fills in <code class="computeroutput"><span class="number">0.0</span></code> for |
| the second argument, which is also probably not what users expect. What |
| can be done? |
| </p> |
| <p> |
| We can say that the <span class="emphasis"><em>arity</em></span> of a calculator expression |
| is the number of arguments it expects, and it is equal to the largest |
| placeholder in the expression. So, the arity of <code class="computeroutput"><span class="identifier">_1</span> |
| <span class="special">*</span> <span class="identifier">_1</span></code> |
| is one, and the arity of <code class="computeroutput"><span class="identifier">_2</span> |
| <span class="special">*</span> <span class="identifier">_2</span></code> |
| is two. We can increase the type-safety of our calculator DSEL by making |
| sure the arity of an expression equals the actual number of arguments |
| supplied. Computing the arity of an expression is simple with the help |
| of Proto transforms. |
| </p> |
| <p> |
| It's straightforward to describe in words how the arity of an expression |
| should be calculated. Consider that calculator expressions can be made |
| of <code class="computeroutput"><span class="identifier">_1</span></code>, <code class="computeroutput"><span class="identifier">_2</span></code>, literals, unary expressions and |
| binary expressions. The following table shows the arities for each of |
| these 5 constituents. |
| </p> |
| <div class="table"> |
| <a name="id2335856"></a><p class="title"><b>Table 16.7. Calculator Sub-Expression Arities</b></p> |
| <div class="table-contents"><table class="table" summary="Calculator Sub-Expression Arities"> |
| <colgroup> |
| <col> |
| <col> |
| </colgroup> |
| <thead><tr> |
| <th> |
| <p> |
| Sub-Expression |
| </p> |
| </th> |
| <th> |
| <p> |
| Arity |
| </p> |
| </th> |
| </tr></thead> |
| <tbody> |
| <tr> |
| <td> |
| <p> |
| Placeholder 1 |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="number">1</span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| Placeholder 2 |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="number">2</span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| Literal |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="number">0</span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| Unary Expression |
| </p> |
| </td> |
| <td> |
| <p> |
| <span class="emphasis"><em>arity of the operand</em></span> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| Binary Expression |
| </p> |
| </td> |
| <td> |
| <p> |
| <span class="emphasis"><em>max arity of the two operands</em></span> |
| </p> |
| </td> |
| </tr> |
| </tbody> |
| </table></div> |
| </div> |
| <br class="table-break"><p> |
| Using this information, we can write the grammar for calculator expressions |
| and attach transforms for computing the arity of each constituent. The |
| code below computes the expression arity as a compile-time integer, using |
| integral wrappers and metafunctions from the Boost MPL Library. The grammar |
| is described below. |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">CalcArity</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="number">0</span><span class="special">></span> <span class="special">>,</span> |
| <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">int_</span><span class="special"><</span><span class="number">1</span><span class="special">>()</span> |
| <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="number">1</span><span class="special">></span> <span class="special">>,</span> |
| <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">int_</span><span class="special"><</span><span class="number">2</span><span class="special">>()</span> |
| <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">_</span><span class="special">>,</span> |
| <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">int_</span><span class="special"><</span><span class="number">0</span><span class="special">>()</span> |
| <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">unary_expr</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> <span class="identifier">CalcArity</span><span class="special">>,</span> |
| <span class="identifier">CalcArity</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child</span><span class="special">)</span> |
| <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">binary_expr</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> <span class="identifier">CalcArity</span><span class="special">,</span> <span class="identifier">CalcArity</span><span class="special">>,</span> |
| <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">max</span><span class="special"><</span><span class="identifier">CalcArity</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_left</span><span class="special">),</span> |
| <span class="identifier">CalcArity</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_right</span><span class="special">)>()</span> |
| <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| </p> |
| <p> |
| When we find a placeholder terminal or a literal, we use an <span class="emphasis"><em>object |
| transform</em></span> such as <code class="computeroutput"><span class="identifier">mpl</span><span class="special">::</span><span class="identifier">int_</span><span class="special"><</span><span class="number">1</span><span class="special">>()</span></code> |
| to create a (default-constructed) compile-time integer representing the |
| arity of that terminal. |
| </p> |
| <p> |
| For unary expressions, we use <code class="computeroutput"><span class="identifier">CalcArity</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child</span><span class="special">)</span></code> which is a <span class="emphasis"><em>callable transform</em></span> |
| that computes the arity of the expression's child. |
| </p> |
| <p> |
| The transform for binary expressions has a few new tricks. Let's look |
| more closely: |
| </p> |
| <pre class="programlisting"><span class="comment">// Compute the left and right arities and</span> |
| <span class="comment">// take the larger of the two.</span> |
| <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">max</span><span class="special"><</span><span class="identifier">CalcArity</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_left</span><span class="special">),</span> |
| <span class="identifier">CalcArity</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_right</span><span class="special">)>()</span> |
| </pre> |
| <p> |
| This is an object transform; it default-constructs ... what exactly? |
| The <code class="computeroutput"><span class="identifier">mpl</span><span class="special">::</span><span class="identifier">max</span><span class="special"><></span></code> |
| template is an MPL metafunction that accepts two compile-time integers. |
| It has a nested <code class="computeroutput"><span class="special">::</span><span class="identifier">type</span></code> |
| typedef (not shown) that is the maximum of the two. But here, we appear |
| to be passing it two things that are <span class="emphasis"><em>not</em></span> compile-time |
| integers; they're Proto callable transforms. Proto is smart enough to |
| recognize that fact. It first evaluates the two nested callable transforms, |
| computing the arities of the left and right child expressions. Then it |
| puts the resulting integers into <code class="computeroutput"><span class="identifier">mpl</span><span class="special">::</span><span class="identifier">max</span><span class="special"><></span></code> and evaluates the metafunction |
| by asking for the nested <code class="computeroutput"><span class="special">::</span><span class="identifier">type</span></code>. That is the type of the object |
| that gets default-constructed and returned. |
| </p> |
| <p> |
| More generally, when evaluating object transforms, Proto looks at the |
| object type and checks whether it is a template specialization, like |
| <code class="computeroutput"><span class="identifier">mpl</span><span class="special">::</span><span class="identifier">max</span><span class="special"><></span></code>. |
| If it is, Proto looks for nested transforms that it can evaluate. After |
| any nested transforms have been evaluated and substituted back into the |
| template, the new template specialization is the result type, unless |
| that type has a nested <code class="computeroutput"><span class="special">::</span><span class="identifier">type</span></code>, in which case that becomes the |
| result. |
| </p> |
| <p> |
| Now that we can calculate the arity of a calculator expression, let's |
| redefine the <code class="computeroutput"><span class="identifier">calculator</span><span class="special"><></span></code> expression wrapper we wrote in |
| the Getting Started guide to use the <code class="computeroutput"><span class="identifier">CalcArity</span></code> |
| grammar and some macros from Boost.MPL to issue compile-time errors when |
| users specify too many or too few arguments. |
| </p> |
| <pre class="programlisting"><span class="comment">// The calculator expression wrapper, as defined in the Hello</span> |
| <span class="comment">// Calculator example in the Getting Started guide. It behaves</span> |
| <span class="comment">// just like the expression it wraps, but with extra operator()</span> |
| <span class="comment">// member functions that evaluate the expression.</span> |
| <span class="comment">// NEW: Use the CalcArity grammar to ensure that the correct</span> |
| <span class="comment">// number of arguments are supplied.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">calculator</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">calculator</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>,</span> <span class="identifier">calculator_domain</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">calculator</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>,</span> <span class="identifier">calculator_domain</span><span class="special">></span> |
| <span class="identifier">base_type</span><span class="special">;</span> |
| |
| <span class="identifier">calculator</span><span class="special">(</span><span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span> <span class="special">=</span> <span class="identifier">Expr</span><span class="special">())</span> |
| <span class="special">:</span> <span class="identifier">base_type</span><span class="special">(</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="keyword">typedef</span> <span class="keyword">double</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="comment">// Use CalcArity to compute the arity of Expr: </span> |
| <span class="keyword">static</span> <span class="keyword">int</span> <span class="keyword">const</span> <span class="identifier">arity</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">result_of</span><span class="special"><</span><span class="identifier">CalcArity</span><span class="special">(</span><span class="identifier">Expr</span><span class="special">)>::</span><span class="identifier">type</span><span class="special">::</span><span class="identifier">value</span><span class="special">;</span> |
| |
| <span class="keyword">double</span> <span class="keyword">operator</span><span class="special">()()</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">BOOST_MPL_ASSERT_RELATION</span><span class="special">(</span><span class="number">0</span><span class="special">,</span> <span class="special">==,</span> <span class="identifier">arity</span><span class="special">);</span> |
| <span class="identifier">calculator_context</span> <span class="identifier">ctx</span><span class="special">;</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">double</span> <span class="keyword">operator</span><span class="special">()(</span><span class="keyword">double</span> <span class="identifier">a1</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">BOOST_MPL_ASSERT_RELATION</span><span class="special">(</span><span class="number">1</span><span class="special">,</span> <span class="special">==,</span> <span class="identifier">arity</span><span class="special">);</span> |
| <span class="identifier">calculator_context</span> <span class="identifier">ctx</span><span class="special">;</span> |
| <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">args</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">a1</span><span class="special">);</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">double</span> <span class="keyword">operator</span><span class="special">()(</span><span class="keyword">double</span> <span class="identifier">a1</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">a2</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">BOOST_MPL_ASSERT_RELATION</span><span class="special">(</span><span class="number">2</span><span class="special">,</span> <span class="special">==,</span> <span class="identifier">arity</span><span class="special">);</span> |
| <span class="identifier">calculator_context</span> <span class="identifier">ctx</span><span class="special">;</span> |
| <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">args</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">a1</span><span class="special">);</span> |
| <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">args</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">a2</span><span class="special">);</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| Note the use of <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">result_of</span><span class="special"><></span></code> to access the return type of |
| the <code class="computeroutput"><span class="identifier">CalcArity</span></code> function |
| object. Since we used compile-time integers in our transforms, the arity |
| of the expression is encoded in the return type of the <code class="computeroutput"><span class="identifier">CalcArity</span></code> function object. Proto grammars |
| are valid TR1-style function objects, so you can use <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">result_of</span><span class="special"><></span></code> to figure out their return types. |
| </p> |
| <p> |
| With our compile-time assertions in place, when users provide too many |
| or too few arguments to a calculator expression, as in: |
| </p> |
| <pre class="programlisting"><span class="special">(</span><span class="identifier">_2</span> <span class="special">*</span> <span class="identifier">_2</span><span class="special">)(</span><span class="number">42</span><span class="special">);</span> <span class="comment">// Oops, too few arguments!</span> |
| </pre> |
| <p> |
| ... they will get a compile-time error message on the line with the assertion |
| that reads something like this<sup>[<a name="id2338005" href="#ftn.id2338005" class="footnote">3</a>]</sup>: |
| </p> |
| <pre class="programlisting">c:\boost\org\trunk\libs\proto\scratch\main.cpp(97) : error C2664: 'boost::mpl::asse |
| rtion_failed' : cannot convert parameter 1 from 'boost::mpl::failed ************boo |
| st::mpl::assert_relation<x,y,__formal>::************' to 'boost::mpl::assert<false> |
| ::type' |
| with |
| [ |
| x=1, |
| y=2, |
| __formal=bool boost::mpl::operator==(boost::mpl::failed,boost::mpl::failed) |
| ] |
| </pre> |
| <p> |
| The point of this exercise was to show that we can write a fairly simple |
| Proto grammar with embedded transforms that is declarative and readable |
| and can compute interesting properties of arbitrarily complicated expressions. |
| But transforms can do more than that. Boost.Xpressive uses transforms |
| to turn expressions into finite state automata for matching regular expressions, |
| and Boost.Spirit uses transforms to build recursive descent parser generators. |
| Proto comes with a collection of built-in transforms that you can use |
| to perform very sophisticated expression manipulations like these. In |
| the next few sections we'll see some of them in action. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_transformation.state"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.state" title="Transforms With State Accumulation">Transforms |
| With State Accumulation</a> |
| </h5></div></div></div> |
| <p> |
| So far, we've only seen examples of grammars with transforms that accept |
| one argument: the expression to transform. But consider for a moment |
| how, in ordinary procedural code, you would turn a binary tree into a |
| linked list. You would start with an empty list. Then, you would recursively |
| convert the right branch to a list, and use the result as the initial |
| state while converting the left branch to a list. That is, you would |
| need a function that takes two parameters: the current node and the list |
| so far. These sorts of <span class="emphasis"><em>accumulation</em></span> problems are |
| quite common when processing trees. The linked list is an example of |
| an accumulation variable or <span class="emphasis"><em>state</em></span>. Each iteration |
| of the algorithm takes the current element and state, applies some binary |
| function to the two and creates a new state. In the STL, this algorithm |
| is called <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">accumulate</span><span class="special">()</span></code>. |
| In many other languages, it is called <span class="emphasis"><em>fold</em></span>. Let's |
| see how to implement a fold algorithm with Proto transforms. |
| </p> |
| <p> |
| All Proto grammars can optionally accept a state parameter in addition |
| to the expression to transform. If you want to fold a tree to a list, |
| you'll need to make use of the state parameter to pass around the list |
| you've built so far. As for the list, the Boost.Fusion library provides |
| a <code class="computeroutput"><span class="identifier">fusion</span><span class="special">::</span><span class="identifier">cons</span><span class="special"><></span></code> |
| type from which you can build heterogeneous lists. The type <code class="computeroutput"><span class="identifier">fusion</span><span class="special">::</span><span class="identifier">nil</span></code> represents an empty list. |
| </p> |
| <p> |
| Below is a grammar that recognizes output expressions like <code class="computeroutput"><span class="identifier">cout_</span> <span class="special"><<</span> |
| <span class="number">42</span> <span class="special"><<</span> |
| <span class="char">'\n'</span></code> and puts the arguments into |
| a Fusion list. It is explained below. |
| </p> |
| <pre class="programlisting"><span class="comment">// Fold the terminals in output statements like</span> |
| <span class="comment">// "cout_ << 42 << '\n'" into a Fusion cons-list.</span> |
| <span class="keyword">struct</span> <span class="identifier">FoldToList</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="comment">// Don't add the ostream terminal to the list</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span> |
| <span class="special">></span> |
| <span class="comment">// Put all other terminals at the head of the</span> |
| <span class="comment">// list that we're building in the "state" parameter</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">cons</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span><span class="special">>(</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span> |
| <span class="special">)</span> |
| <span class="special">></span> |
| <span class="comment">// For left-shift operations, first fold the right</span> |
| <span class="comment">// child to a list using the current state. Use</span> |
| <span class="comment">// the result as the state parameter when folding</span> |
| <span class="comment">// the left child to a list.</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_left</span><span class="special"><</span><span class="identifier">FoldToList</span><span class="special">,</span> <span class="identifier">FoldToList</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">FoldToList</span><span class="special">(</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_left</span> |
| <span class="special">,</span> <span class="identifier">FoldToList</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_right</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span><span class="special">)</span> |
| <span class="special">)</span> |
| <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| Before reading on, see if you can apply what you know already about object, |
| callable and primitive transforms to figure out how this grammar works. |
| </p> |
| <p> |
| When you use the <code class="computeroutput"><span class="identifier">FoldToList</span></code> |
| function, you'll need to pass two arguments: the expression to fold, |
| and the initial state: an empty list. Those two arguments get passed |
| around to each transform. We learned previously that <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span></code> |
| is a primitive transform that accepts a terminal expression and extracts |
| its value. What we didn't know until now was that it also accepts the |
| current state <span class="emphasis"><em>and ignores it</em></span>. <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span></code> |
| is also a primitive transform. It accepts the current expression, which |
| it ignores, and the current state, which it returns. |
| </p> |
| <p> |
| When we find a terminal, we stick it at the head of the cons list, using |
| the current state as the tail of the list. (The first alternate causes |
| the <code class="computeroutput"><span class="identifier">ostream</span></code> to be skipped. |
| We don't want <code class="computeroutput"><span class="identifier">cout</span></code> in |
| the list.) When we find a shift-left node, we apply the following transform: |
| </p> |
| <pre class="programlisting"><span class="comment">// Fold the right child and use the result as</span> |
| <span class="comment">// state while folding the right.</span> |
| <span class="identifier">FoldToList</span><span class="special">(</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_left</span> |
| <span class="special">,</span> <span class="identifier">FoldToList</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_right</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span><span class="special">)</span> |
| <span class="special">)</span> |
| </pre> |
| <p> |
| You can read this transform as follows: using the current state, fold |
| the right child to a list. Use the new list as the state while folding |
| the left child to a list. |
| </p> |
| <div class="tip"><table border="0" summary="Tip"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="../../../doc/src/images/tip.png"></td> |
| <th align="left">Tip</th> |
| </tr> |
| <tr><td align="left" valign="top"> |
| <p> |
| If your compiler is Microsoft Visual C++, you'll find that the above |
| transform does not compile. The compiler has bugs with its handling |
| of nested function types. You can work around the bug by wrapping the |
| inner transform in <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">call</span><span class="special"><></span></code> as follows: |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="identifier">FoldToList</span><span class="special">(</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_left</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">call</span><span class="special"><</span><span class="identifier">FoldToList</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_right</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span><span class="special">)></span> |
| <span class="special">)</span> |
| </pre> |
| <p> |
| </p> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">call</span><span class="special"><></span></code> |
| turns a callable transform into a primitive transform, but more on |
| that later. |
| </p> |
| </td></tr> |
| </table></div> |
| <p> |
| Now that we have defined the <code class="computeroutput"><span class="identifier">FoldToList</span></code> |
| function object, we can use it to turn output expressions into lists |
| as follows: |
| </p> |
| <pre class="programlisting"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&>::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">cout_</span> <span class="special">=</span> <span class="special">{</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">};</span> |
| |
| <span class="comment">// This is the type of the list we build below</span> |
| <span class="keyword">typedef</span> |
| <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">cons</span><span class="special"><</span> |
| <span class="keyword">int</span> |
| <span class="special">,</span> <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">cons</span><span class="special"><</span> |
| <span class="keyword">double</span> |
| <span class="special">,</span> <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">cons</span><span class="special"><</span> |
| <span class="keyword">char</span> |
| <span class="special">,</span> <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">nil</span> |
| <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">></span> |
| <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="comment">// Fold an output expression into a Fusion list, using</span> |
| <span class="comment">// fusion::nil as the initial state of the transformation.</span> |
| <span class="identifier">FoldToList</span> <span class="identifier">to_list</span><span class="special">;</span> |
| <span class="identifier">result_type</span> <span class="identifier">args</span> <span class="special">=</span> <span class="identifier">to_list</span><span class="special">(</span><span class="identifier">cout_</span> <span class="special"><<</span> <span class="number">1</span> <span class="special"><<</span> <span class="number">3.14</span> <span class="special"><<</span> <span class="char">'\n'</span><span class="special">,</span> <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">nil</span><span class="special">());</span> |
| |
| <span class="comment">// Now "args" is the list: {1, 3.14, '\n'}</span> |
| </pre> |
| <p> |
| When writing transforms, "fold" is such a basic operation that |
| Proto provides a number of built-in fold transforms. We'll get to them |
| later. For now, rest assured that you won't always have to stretch your |
| brain so far to do such basic things. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_transformation.data"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.data" title="Passing Auxiliary Data to Transforms">Passing |
| Auxiliary Data to Transforms</a> |
| </h5></div></div></div> |
| <p> |
| In the last section, we saw that we can pass a second parameter to grammars |
| with transforms: an accumulation variable or <span class="emphasis"><em>state</em></span> |
| that gets updated as your transform executes. There are times when your |
| transforms will need to access auxiliary data that does <span class="emphasis"><em>not</em></span> |
| accumulate, so bundling it with the state parameter is impractical. Instead, |
| you can pass auxiliary data as a third parameter, known as the <span class="emphasis"><em>data</em></span> |
| parameter. Below we show an example involving string processing where |
| the data parameter is essential. |
| </p> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| All Proto grammars are function objects that take one, two or three |
| arguments: the expression, the state, and the data. There are no additional |
| arguments to know about, we promise. In Haskell, there is set of tree |
| traversal technologies known collectively as <a class="link" href="users_guide.html#boost_proto.users_guide.resources.SYB"><span class="quote">“<span class="quote">Scrap |
| Your Boilerplate</span>”</span></a>. In that framework, there are also |
| three parameters: the term, the accumulator, and the context. These |
| are Proto's expression, state and data parameters under different names. |
| </p></td></tr> |
| </table></div> |
| <p> |
| Expression templates are often used as an optimization to eliminate temporary |
| objects. Consider the problem of string concatenation: a series of concatenations |
| would result in the needless creation of temporary strings. We can use |
| Proto to make string concatenation very efficient. To make the problem |
| more interesting, we can apply a locale-sensitive transformation to each |
| character during the concatenation. The locale information will be passed |
| as the data parameter. |
| </p> |
| <p> |
| Consider the following expression template: |
| </p> |
| <pre class="programlisting"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">lit</span><span class="special">(</span><span class="string">"hello"</span><span class="special">)</span> <span class="special">+</span> <span class="string">" "</span> <span class="special">+</span> <span class="string">"world"</span><span class="special">;</span> |
| </pre> |
| <p> |
| We would like to concatenate this string into a statically allocated |
| wide character buffer, widening each character in turn using the specified |
| locale. The first step is to write a grammar that describes this expression, |
| with transforms that calculate the total string length. Here it is: |
| </p> |
| <pre class="programlisting"><span class="comment">// A grammar that matches string concatenation expressions, and</span> |
| <span class="comment">// a transform that calculates the total string length.</span> |
| <span class="keyword">struct</span> <span class="identifier">StringLength</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="comment">// When you find a character array ...</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">char</span><span class="special">[</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">N</span><span class="special">]></span> |
| <span class="comment">// ... the length is the size of the array minus 1.</span> |
| <span class="special">,</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">prior</span><span class="special"><</span><span class="identifier">mpl</span><span class="special">::</span><span class="identifier">sizeof_</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">></span> <span class="special">>()</span> |
| <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="comment">// The length of a concatenated string is ...</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><span class="identifier">StringLength</span><span class="special">,</span> <span class="identifier">StringLength</span><span class="special">></span> |
| <span class="comment">// ... the sum of the lengths of each sub-string.</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">fold</span><span class="special"><</span> |
| <span class="identifier">_</span> |
| <span class="special">,</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">size_t</span><span class="special"><</span><span class="number">0</span><span class="special">>()</span> |
| <span class="special">,</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><span class="identifier">StringLength</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span><span class="special">>()</span> |
| <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| Notice the use of <code class="computeroutput"><a class="link" href="../boost/proto/fold.html" title="Struct template fold">proto::fold<></a></code>. It is a primitive |
| transform that takes a sequence, a state, and function, just like <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">accumulate</span><span class="special">()</span></code>. |
| The three template parameters are transforms. The first yields the sequence |
| of expressions over which to fold, the second yields the initial state |
| of the fold, and the third is the function to apply at each iteration. |
| The use of <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span></code> as the first parameter might have |
| you confused. In addition to being Proto's wildcard, <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span></code> |
| is also a primitive transform that returns the current expression, which |
| (if it is a non-terminal) is a sequence of its child expressions. |
| </p> |
| <p> |
| Next, we need a function object that accepts a narrow string, a wide |
| character buffer, and a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ctype</span><span class="special"><></span></code> facet for doing the locale-specific |
| stuff. It's fairly straightforward. |
| </p> |
| <pre class="programlisting"><span class="comment">// A function object that writes a narrow string</span> |
| <span class="comment">// into a wide buffer.</span> |
| <span class="keyword">struct</span> <span class="identifier">WidenCopy</span> <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable</span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">wchar_t</span> <span class="special">*</span><span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="keyword">wchar_t</span> <span class="special">*</span> |
| <span class="keyword">operator</span><span class="special">()(</span><span class="keyword">char</span> <span class="keyword">const</span> <span class="special">*</span><span class="identifier">str</span><span class="special">,</span> <span class="keyword">wchar_t</span> <span class="special">*</span><span class="identifier">buf</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ctype</span><span class="special"><</span><span class="keyword">char</span><span class="special">></span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">ct</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">for</span><span class="special">(;</span> <span class="special">*</span><span class="identifier">str</span><span class="special">;</span> <span class="special">++</span><span class="identifier">str</span><span class="special">,</span> <span class="special">++</span><span class="identifier">buf</span><span class="special">)</span> |
| <span class="special">*</span><span class="identifier">buf</span> <span class="special">=</span> <span class="identifier">ct</span><span class="special">.</span><span class="identifier">widen</span><span class="special">(*</span><span class="identifier">str</span><span class="special">);</span> |
| <span class="keyword">return</span> <span class="identifier">buf</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| </pre> |
| <p> |
| Finally, we need some transforms that actually walk the concatenated |
| string expression, widens the characters and writes them to a buffer. |
| We will pass a <code class="computeroutput"><span class="keyword">wchar_t</span><span class="special">*</span></code> |
| as the state parameter and update it as we go. We'll also pass the <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ctype</span><span class="special"><></span></code> |
| facet as the data parameter. It looks like this: |
| </p> |
| <pre class="programlisting"><span class="comment">// Write concatenated strings into a buffer, widening</span> |
| <span class="comment">// them as we go.</span> |
| <span class="keyword">struct</span> <span class="identifier">StringCopy</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">char</span><span class="special">[</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">N</span><span class="special">]></span> |
| <span class="special">,</span> <span class="identifier">WidenCopy</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_data</span><span class="special">)</span> |
| <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><span class="identifier">StringCopy</span><span class="special">,</span> <span class="identifier">StringCopy</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">StringCopy</span><span class="special">(</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_right</span> |
| <span class="special">,</span> <span class="identifier">StringCopy</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_left</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_data</span><span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_data</span> |
| <span class="special">)</span> |
| <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| Let's look more closely at the transform associated with non-terminals: |
| </p> |
| <pre class="programlisting"><span class="identifier">StringCopy</span><span class="special">(</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_right</span> |
| <span class="special">,</span> <span class="identifier">StringCopy</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_left</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_data</span><span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_data</span> |
| <span class="special">)</span> |
| </pre> |
| <p> |
| This bears a resemblance to the transform in the previous section that |
| folded an expression tree into a list. First we recurse on the left child, |
| writing its strings into the <code class="computeroutput"><span class="keyword">wchar_t</span><span class="special">*</span></code> passed in as the state parameter. That |
| returns the new value of the <code class="computeroutput"><span class="keyword">wchar_t</span><span class="special">*</span></code>, which is passed as state while transforming |
| the right child. Both invocations receive the same <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ctype</span><span class="special"><></span></code>, which is passed in as the data |
| parameter. |
| </p> |
| <p> |
| With these pieces in our pocket, we can implement our concatenate-and-widen |
| function as follows: |
| </p> |
| <pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">void</span> <span class="identifier">widen</span><span class="special">(</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span> <span class="special">)</span> |
| <span class="special">{</span> |
| <span class="comment">// Make sure the expression conforms to our grammar</span> |
| <span class="identifier">BOOST_MPL_ASSERT</span><span class="special">((</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">StringLength</span><span class="special">></span> <span class="special">));</span> |
| |
| <span class="comment">// Calculate the length of the string and allocate a buffer statically</span> |
| <span class="keyword">static</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="keyword">const</span> <span class="identifier">length</span> <span class="special">=</span> |
| <span class="identifier">boost</span><span class="special">::</span><span class="identifier">result_of</span><span class="special"><</span><span class="identifier">StringLength</span><span class="special">(</span><span class="identifier">Expr</span><span class="special">)>::</span><span class="identifier">type</span><span class="special">::</span><span class="identifier">value</span><span class="special">;</span> |
| <span class="keyword">wchar_t</span> <span class="identifier">buffer</span><span class="special">[</span> <span class="identifier">length</span> <span class="special">+</span> <span class="number">1</span> <span class="special">]</span> <span class="special">=</span> <span class="special">{</span><span class="identifier">L</span><span class="char">'\0'</span><span class="special">};</span> |
| |
| <span class="comment">// Get the current ctype facet</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">locale</span> <span class="identifier">loc</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">ctype</span><span class="special"><</span><span class="keyword">char</span><span class="special">></span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">ct</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">use_facet</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ctype</span><span class="special"><</span><span class="keyword">char</span><span class="special">></span> <span class="special">>(</span><span class="identifier">loc</span><span class="special">));</span> |
| |
| <span class="comment">// Concatenate and widen the string expression</span> |
| <span class="identifier">StringCopy</span><span class="special">()(</span><span class="identifier">expr</span><span class="special">,</span> <span class="special">&</span><span class="identifier">buffer</span><span class="special">[</span><span class="number">0</span><span class="special">],</span> <span class="identifier">ct</span><span class="special">);</span> |
| |
| <span class="comment">// Write out the buffer.</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">wcout</span> <span class="special"><<</span> <span class="identifier">buffer</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="identifier">widen</span><span class="special">(</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">lit</span><span class="special">(</span><span class="string">"hello"</span><span class="special">)</span> <span class="special">+</span> <span class="string">" "</span> <span class="special">+</span> <span class="string">"world"</span> <span class="special">);</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| The above code displays: |
| </p> |
| <pre class="programlisting">hello world |
| </pre> |
| <p> |
| This is a rather round-about way of demonstrating that you can pass extra |
| data to a transform as a third parameter. There are no restrictions on |
| what this parameter can be, and (unlike the state parameter) Proto will |
| never mess with it. |
| </p> |
| <a name="boost_proto.users_guide.back_end.expression_transformation.data.implicit_parameters_to_primitive_transforms"></a><h6> |
| <a name="boost_proto.users_guide.back_end.expression_transformation.data.implicit_parameters_to_primitive_transforms-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.data.implicit_parameters_to_primitive_transforms">Implicit |
| Parameters to Primitive Transforms</a> |
| </h6> |
| <p> |
| Let's use the above example to illustrate some other niceties of Proto |
| transforms. We've seen that grammars, when used as function objects, |
| can accept up to 3 parameters, and that when using these grammars in |
| callable transforms, you can also specify up to 3 parameters. Let's take |
| another look at the transform associated with non-terminals above: |
| </p> |
| <pre class="programlisting"><span class="identifier">StringCopy</span><span class="special">(</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_right</span> |
| <span class="special">,</span> <span class="identifier">StringCopy</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_left</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_data</span><span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_data</span> |
| <span class="special">)</span> |
| </pre> |
| <p> |
| Here we specify all three parameters to both invocations of the <code class="computeroutput"><span class="identifier">StringCopy</span></code> grammar. But we don't have |
| to specify all three. If we don't specify a third parameter, <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_data</span></code> is assumed. Likewise for the |
| second parameter and <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span></code>. |
| So the above transform could have been written more simply as: |
| </p> |
| <pre class="programlisting"><span class="identifier">StringCopy</span><span class="special">(</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_right</span> |
| <span class="special">,</span> <span class="identifier">StringCopy</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_left</span><span class="special">)</span> |
| <span class="special">)</span> |
| </pre> |
| <p> |
| The same is true for any primitive transform. The following are all equivalent: |
| </p> |
| <div class="table"> |
| <a name="id2342270"></a><p class="title"><b>Table 16.8. Implicit Parameters to Primitive Transforms</b></p> |
| <div class="table-contents"><table class="table" summary="Implicit Parameters to Primitive Transforms"> |
| <colgroup><col></colgroup> |
| <thead><tr><th> |
| <p> |
| Equivalent Transforms |
| </p> |
| </th></tr></thead> |
| <tbody> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> |
| <span class="identifier">StringCopy</span><span class="special">></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> |
| <span class="identifier">StringCopy</span><span class="special">()></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> |
| <span class="identifier">StringCopy</span><span class="special">(</span><span class="identifier">_</span><span class="special">)></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> |
| <span class="identifier">StringCopy</span><span class="special">(</span><span class="identifier">_</span><span class="special">,</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span><span class="special">)></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> |
| <span class="identifier">StringCopy</span><span class="special">(</span><span class="identifier">_</span><span class="special">,</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span><span class="special">,</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_data</span><span class="special">)></span></code> |
| </p> |
| </td></tr> |
| </tbody> |
| </table></div> |
| </div> |
| <br class="table-break"><div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"> |
| <p> |
| <span class="bold"><strong>Grammars Are Primitive Transforms Are Function |
| Objects</strong></span> |
| </p> |
| <p> |
| So far, we've said that all Proto grammars are function objects. But |
| it's more accurate to say that Proto grammars are primitive transforms |
| -- a special kind of function object that takes between 1 and 3 arguments, |
| and that Proto knows to treat specially when used in a callable transform, |
| as in the table above. |
| </p> |
| </td></tr> |
| </table></div> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"> |
| <p> |
| <span class="bold"><strong>Not All Function Objects Are Primitive Transforms</strong></span> |
| </p> |
| <p> |
| You might be tempted now to drop the <code class="computeroutput"><span class="identifier">_state</span></code> |
| and <code class="computeroutput"><span class="identifier">_data</span></code> parameters |
| to <code class="computeroutput"><span class="identifier">WidenCopy</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">,</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span><span class="special">,</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_data</span><span class="special">)</span></code>. |
| That would be an error. <code class="computeroutput"><span class="identifier">WidenCopy</span></code> |
| is just a plain function object, not a primitive transform, so you |
| must specify all its arguments. We'll see later how to write your own |
| primitive transforms. |
| </p> |
| </td></tr> |
| </table></div> |
| <p> |
| Once you know that primitive transforms will always receive all three |
| parameters -- expression, state, and data -- it makes things possible |
| that wouldn't be otherwise. For instance, consider that for binary expressions, |
| these two transforms are equivalent. Can you see why? |
| </p> |
| <div class="table"> |
| <a name="id2342784"></a><p class="title"><b>Table 16.9. Two Equivalent Transforms</b></p> |
| <div class="table-contents"><table class="table" summary="Two Equivalent Transforms"> |
| <colgroup> |
| <col> |
| <col> |
| </colgroup> |
| <thead><tr> |
| <th> |
| <p> |
| Without <code class="literal">proto::fold<></code> |
| </p> |
| </th> |
| <th> |
| <p> |
| With <code class="literal">proto::fold<></code> |
| </p> |
| </th> |
| </tr></thead> |
| <tbody><tr> |
| <td> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="identifier">StringCopy</span><span class="special">(</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_right</span> |
| <span class="special">,</span> <span class="identifier">StringCopy</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_left</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_data</span><span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_data</span> |
| <span class="special">)</span></pre> |
| <p> |
| </p> |
| </td> |
| <td> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">fold</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span><span class="special">,</span> <span class="identifier">StringCopy</span><span class="special">></span></pre> |
| <p> |
| </p> |
| </td> |
| </tr></tbody> |
| </table></div> |
| </div> |
| <br class="table-break"> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_transformation.canned_transforms"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.canned_transforms" title="Proto's Built-In Transforms">Proto's |
| Built-In Transforms</a> |
| </h5></div></div></div> |
| <p> |
| Primitive transforms are the building blocks for more interesting composite |
| transforms. Proto defines a bunch of generally useful primitive transforms. |
| They are summarized below. |
| </p> |
| <div class="variablelist"> |
| <p class="title"><b></b></p> |
| <dl> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/_value.html" title="Struct _value">proto::_value</a></code></span></dt> |
| <dd><p> |
| Given a terminal expression, return the value of the terminal. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/_child_c.html" title="Struct template _child_c">proto::_child_c<></a></code></span></dt> |
| <dd><p> |
| Given a non-terminal expression, <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child_c</span><span class="special"><</span><em class="replaceable"><code>N</code></em><span class="special">></span></code> returns the <em class="replaceable"><code>N</code></em>-th |
| child. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="reference.html#boost.proto._child">proto::_child</a></code></span></dt> |
| <dd><p> |
| A synonym for <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child_c</span><span class="special"><</span><span class="number">0</span><span class="special">></span></code>. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="reference.html#boost.proto._left">proto::_left</a></code></span></dt> |
| <dd><p> |
| A synonym for <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child_c</span><span class="special"><</span><span class="number">0</span><span class="special">></span></code>. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="reference.html#boost.proto._right">proto::_right</a></code></span></dt> |
| <dd><p> |
| A synonym for <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child_c</span><span class="special"><</span><span class="number">1</span><span class="special">></span></code>. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/_expr.html" title="Struct _expr">proto::_expr</a></code></span></dt> |
| <dd><p> |
| Returns the current expression unmodified. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/_state.html" title="Struct _state">proto::_state</a></code></span></dt> |
| <dd><p> |
| Returns the current state unmodified. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/_data.html" title="Struct _data">proto::_data</a></code></span></dt> |
| <dd><p> |
| Returns the current data unmodified. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/call.html" title="Struct template call">proto::call<></a></code></span></dt> |
| <dd><p> |
| For a given callable transform <code class="computeroutput"><em class="replaceable"><code>CT</code></em></code>, |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">call</span><span class="special"><</span><em class="replaceable"><code>CT</code></em><span class="special">></span></code> turns the callable transform |
| into a primitive transform. This is useful for disambiguating callable |
| transforms from object transforms, and also for working around |
| compiler bugs with nested function types. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/make.html" title="Struct template make">proto::make<></a></code></span></dt> |
| <dd><p> |
| For a given object transform <code class="computeroutput"><em class="replaceable"><code>OT</code></em></code>, |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">make</span><span class="special"><</span><em class="replaceable"><code>OT</code></em><span class="special">></span></code> turns the object transform |
| into a primitive transform. This is useful for disambiguating object |
| transforms from callable transforms, and also for working around |
| compiler bugs with nested function types. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/_default.html" title="Struct template _default">proto::_default<></a></code></span></dt> |
| <dd><p> |
| Given a grammar <em class="replaceable"><code>G</code></em>, <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_default</span><span class="special"><</span><em class="replaceable"><code>G</code></em><span class="special">></span></code> evaluates the current node |
| according to the standard C++ meaning of the operation the node |
| represents. For instance, if the current node is a binary plus |
| node, the two children will both be evaluated according to <code class="computeroutput"><em class="replaceable"><code>G</code></em></code> |
| and the results will be added and returned. The return type is |
| deduced with the help of the Boost.Typeof library. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/fold.html" title="Struct template fold">proto::fold<></a></code></span></dt> |
| <dd><p> |
| Given three transforms <code class="computeroutput"><em class="replaceable"><code>ET</code></em></code>, |
| <code class="computeroutput"><em class="replaceable"><code>ST</code></em></code>, and <code class="computeroutput"><em class="replaceable"><code>FT</code></em></code>, |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">fold</span><span class="special"><</span><em class="replaceable"><code>ET</code></em><span class="special">,</span> <em class="replaceable"><code>ST</code></em><span class="special">,</span> <em class="replaceable"><code>FT</code></em><span class="special">></span></code> first evaluates <code class="computeroutput"><em class="replaceable"><code>ET</code></em></code> |
| to obtain a Fusion sequence and <code class="computeroutput"><em class="replaceable"><code>ST</code></em></code> |
| to obtain an initial state for the fold, and then evaluates <code class="computeroutput"><em class="replaceable"><code>FT</code></em></code> |
| for each element in the sequence to generate the next state from |
| the previous. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/reverse_fold.html" title="Struct template reverse_fold">proto::reverse_fold<></a></code></span></dt> |
| <dd><p> |
| Like <code class="computeroutput"><a class="link" href="../boost/proto/fold.html" title="Struct template fold">proto::fold<></a></code>, except the |
| elements in the Fusion sequence are iterated in reverse order. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/fold_tree.html" title="Struct template fold_tree">proto::fold_tree<></a></code></span></dt> |
| <dd><p> |
| Like <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">fold</span><span class="special"><</span><em class="replaceable"><code>ET</code></em><span class="special">,</span> <em class="replaceable"><code>ST</code></em><span class="special">,</span> <em class="replaceable"><code>FT</code></em><span class="special">></span></code>, except that the result of |
| the <code class="computeroutput"><em class="replaceable"><code>ET</code></em></code> transform is treated |
| as an expression tree that is <span class="emphasis"><em>flattened</em></span> to |
| generate the sequence to be folded. Flattening an expression tree |
| causes child nodes with the same tag type as the parent to be put |
| into sequence. For instance, <code class="computeroutput"><span class="identifier">a</span> |
| <span class="special">>></span> <span class="identifier">b</span> |
| <span class="special">>></span> <span class="identifier">c</span></code> |
| would be flattened to the sequence [<code class="computeroutput"><span class="identifier">a</span></code>, |
| <code class="computeroutput"><span class="identifier">b</span></code>, <code class="computeroutput"><span class="identifier">c</span></code>], and this is the sequence |
| that would be folded. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/reverse_fold_tree.html" title="Struct template reverse_fold_tree">proto::reverse_fold_tree<></a></code></span></dt> |
| <dd><p> |
| Like <code class="computeroutput"><a class="link" href="../boost/proto/fold_tree.html" title="Struct template fold_tree">proto::fold_tree<></a></code>, except that |
| the flattened sequence is iterated in reverse order. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/lazy.html" title="Struct template lazy">proto::lazy<></a></code></span></dt> |
| <dd><p> |
| A combination of <code class="computeroutput"><a class="link" href="../boost/proto/make.html" title="Struct template make">proto::make<></a></code> |
| and <code class="computeroutput"><a class="link" href="../boost/proto/call.html" title="Struct template call">proto::call<></a></code> that is useful |
| when the nature of the transform depends on the expression, state |
| and/or data parameters. <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">lazy</span><span class="special"><</span><span class="identifier">R</span><span class="special">(</span><span class="identifier">A0</span><span class="special">,</span><span class="identifier">A1</span><span class="special">...</span><span class="identifier">An</span><span class="special">)></span></code> first evaluates <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">make</span><span class="special"><</span><span class="identifier">R</span><span class="special">()></span></code> |
| to compute a callable type <code class="computeroutput"><span class="identifier">R2</span></code>. |
| Then, it evaluates <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">call</span><span class="special"><</span><span class="identifier">R2</span><span class="special">(</span><span class="identifier">A0</span><span class="special">,</span><span class="identifier">A1</span><span class="special">...</span><span class="identifier">An</span><span class="special">)></span></code>. |
| </p></dd> |
| </dl> |
| </div> |
| <a name="boost_proto.users_guide.back_end.expression_transformation.canned_transforms.all_grammars_are_primitive_transforms"></a><h6> |
| <a name="boost_proto.users_guide.back_end.expression_transformation.canned_transforms.all_grammars_are_primitive_transforms-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.canned_transforms.all_grammars_are_primitive_transforms">All |
| Grammars Are Primitive Transforms</a> |
| </h6> |
| <p> |
| In addition to the above primitive transforms, all of Proto's grammar |
| elements are also primitive transforms. Their behaviors are described |
| below. |
| </p> |
| <div class="variablelist"> |
| <p class="title"><b></b></p> |
| <dl> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/_.html" title="Struct _">proto::_</a></code></span></dt> |
| <dd><p> |
| Return the current expression unmodified. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/or_.html" title="Struct template or_">proto::or_<></a></code></span></dt> |
| <dd><p> |
| For the specified set of alternate sub-grammars, find the one that |
| matches the given expression and apply its associated transform. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/and_.html" title="Struct template and_">proto::and_<></a></code></span></dt> |
| <dd><p> |
| For the given set of sub-grammars, apply all the associated transforms |
| and return the result of the last. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/not_.html" title="Struct template not_">proto::not_<></a></code></span></dt> |
| <dd><p> |
| Return the current expression unmodified. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/if_.html" title="Struct template if_">proto::if_<></a></code></span></dt> |
| <dd><p> |
| Given three transforms, evaluate the first and treat the result |
| as a compile-time Boolean value. If it is true, evaluate the second |
| transform. Otherwise, evaluate the third. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/switch_.html" title="Struct template switch_">proto::switch_<></a></code></span></dt> |
| <dd><p> |
| As with <code class="computeroutput"><a class="link" href="../boost/proto/or_.html" title="Struct template or_">proto::or_<></a></code>, find the sub-grammar |
| that matches the given expression and apply its associated transform. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/terminal.html" title="Struct template terminal">proto::terminal<></a></code></span></dt> |
| <dd><p> |
| Return the current terminal expression unmodified. |
| </p></dd> |
| <dt><span class="term"> <code class="computeroutput"><a class="link" href="../boost/proto/plus.html" title="Struct template plus">proto::plus<></a></code>, <code class="computeroutput"><a class="link" href="../boost/proto/nary_expr.html" title="Struct template nary_expr">proto::nary_expr<></a></code>, |
| et. al.</span></dt> |
| <dd><p> |
| A Proto grammar that matches a non-terminal such as <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><em class="replaceable"><code>G0</code></em><span class="special">,</span> <em class="replaceable"><code>G1</code></em><span class="special">></span></code>, when used as a primitive transform, |
| creates a new plus node where the left child is transformed according |
| to <code class="computeroutput"><em class="replaceable"><code>G0</code></em></code> and the right child |
| with <code class="computeroutput"><em class="replaceable"><code>G1</code></em></code>. |
| </p></dd> |
| </dl> |
| </div> |
| <a name="boost_proto.users_guide.back_end.expression_transformation.canned_transforms.the_pass_through_transform"></a><h6> |
| <a name="boost_proto.users_guide.back_end.expression_transformation.canned_transforms.the_pass_through_transform-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.canned_transforms.the_pass_through_transform">The |
| Pass-Through Transform</a> |
| </h6> |
| <p> |
| Note the primitive transform associated with grammar elements such as |
| <code class="computeroutput"><a class="link" href="../boost/proto/plus.html" title="Struct template plus">proto::plus<></a></code> described above. |
| They possess a so-called <span class="emphasis"><em>pass-through</em></span> transform. |
| The pass-through transform accepts an expression of a certain tag type |
| (say, <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">plus</span></code>) and creates a new expression |
| of the same tag type, where each child expression is transformed according |
| to the corresponding child grammar of the pass-through transform. So |
| for instance this grammar ... |
| </p> |
| <pre class="programlisting"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">function</span><span class="special"><</span> <span class="identifier">X</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">vararg</span><span class="special"><</span><span class="identifier">Y</span><span class="special">></span> <span class="special">></span> |
| </pre> |
| <p> |
| ... matches function expressions where the first child matches the <code class="computeroutput"><span class="identifier">X</span></code> grammar and the rest match the <code class="computeroutput"><span class="identifier">Y</span></code> grammar. When used as a transform, |
| the above grammar will create a new function expression where the first |
| child is transformed according to <code class="computeroutput"><span class="identifier">X</span></code> |
| and the rest are transformed according to <code class="computeroutput"><span class="identifier">Y</span></code>. |
| </p> |
| <p> |
| The following class templates in Proto can be used as grammars with pass-through |
| transforms: |
| </p> |
| <div class="table"> |
| <a name="id2344654"></a><p class="title"><b>Table 16.10. Class Templates With Pass-Through Transforms</b></p> |
| <div class="table-contents"><table class="table" summary="Class Templates With Pass-Through Transforms"> |
| <colgroup><col></colgroup> |
| <thead><tr><th> |
| <p> |
| Templates with Pass-Through Transforms |
| </p> |
| </th></tr></thead> |
| <tbody> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">unary_plus</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">negate</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">dereference</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">complement</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">address_of</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">logical_not</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">pre_inc</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">pre_dec</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">post_inc</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">post_dec</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_left</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_right</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">multiplies</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">divides</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">modulus</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">minus</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">less</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">greater</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">less_equal</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">greater_equal</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">equal_to</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">not_equal_to</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">logical_or</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">logical_and</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">bitwise_and</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">bitwise_or</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">bitwise_xor</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">comma</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">mem_ptr</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">assign</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_left_assign</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">shift_right_assign</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">multiplies_assign</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">divides_assign</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">modulus_assign</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus_assign</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">minus_assign</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">bitwise_and_assign</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">bitwise_or_assign</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">bitwise_xor_assign</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">subscript</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">if_else_</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">function</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">unary_expr</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">binary_expr</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| <tr><td> |
| <p> |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">nary_expr</span><span class="special"><></span></code> |
| </p> |
| </td></tr> |
| </tbody> |
| </table></div> |
| </div> |
| <br class="table-break"><a name="boost_proto.users_guide.back_end.expression_transformation.canned_transforms.the_many_roles_of_proto_operator_metafunctions"></a><h6> |
| <a name="boost_proto.users_guide.back_end.expression_transformation.canned_transforms.the_many_roles_of_proto_operator_metafunctions-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.canned_transforms.the_many_roles_of_proto_operator_metafunctions">The |
| Many Roles of Proto Operator Metafunctions</a> |
| </h6> |
| <p> |
| We've seen templates such as <code class="computeroutput"><a class="link" href="../boost/proto/terminal.html" title="Struct template terminal">proto::terminal<></a></code>, |
| <code class="computeroutput"><a class="link" href="../boost/proto/plus.html" title="Struct template plus">proto::plus<></a></code> and <code class="computeroutput"><a class="link" href="../boost/proto/nary_expr.html" title="Struct template nary_expr">proto::nary_expr<></a></code> |
| fill many roles. They are metafunction that generate expression types. |
| They are grammars that match expression types. And they are primitive |
| transforms. The following code samples show examples of each. |
| </p> |
| <p> |
| <span class="bold"><strong>As Metafunctions ...</strong></span> |
| </p> |
| <pre class="programlisting"><span class="comment">// proto::terminal<> and proto::plus<> are metafunctions</span> |
| <span class="comment">// that generate expression types:</span> |
| <span class="keyword">typedef</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">>::</span><span class="identifier">type</span> <span class="identifier">int_</span><span class="special">;</span> |
| <span class="keyword">typedef</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><span class="identifier">int_</span><span class="special">,</span> <span class="identifier">int_</span><span class="special">>::</span><span class="identifier">type</span> <span class="identifier">plus_</span><span class="special">;</span> |
| |
| <span class="identifier">int_</span> <span class="identifier">i</span> <span class="special">=</span> <span class="special">{</span><span class="number">42</span><span class="special">},</span> <span class="identifier">j</span> <span class="special">=</span> <span class="special">{</span><span class="number">24</span><span class="special">};</span> |
| <span class="identifier">plus_</span> <span class="identifier">p</span> <span class="special">=</span> <span class="special">{</span><span class="identifier">i</span><span class="special">,</span> <span class="identifier">j</span><span class="special">};</span> |
| </pre> |
| <p> |
| <span class="bold"><strong>As Grammars ...</strong></span> |
| </p> |
| <pre class="programlisting"><span class="comment">// proto::terminal<> and proto::plus<> are grammars that</span> |
| <span class="comment">// match expression types</span> |
| <span class="keyword">struct</span> <span class="identifier">Int</span> <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="special">{};</span> |
| <span class="keyword">struct</span> <span class="identifier">Plus</span> <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><span class="identifier">Int</span><span class="special">,</span> <span class="identifier">Int</span><span class="special">></span> <span class="special">{};</span> |
| |
| <span class="identifier">BOOST_MPL_ASSERT</span><span class="special">((</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span> <span class="identifier">int_</span><span class="special">,</span> <span class="identifier">Int</span> <span class="special">></span> <span class="special">));</span> |
| <span class="identifier">BOOST_MPL_ASSERT</span><span class="special">((</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span> <span class="identifier">plus_</span><span class="special">,</span> <span class="identifier">Plus</span> <span class="special">></span> <span class="special">));</span> |
| </pre> |
| <p> |
| <span class="bold"><strong>As Primitive Transforms ...</strong></span> |
| </p> |
| <pre class="programlisting"><span class="comment">// A transform that removes all unary_plus nodes in an expression</span> |
| <span class="keyword">struct</span> <span class="identifier">RemoveUnaryPlus</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">unary_plus</span><span class="special"><</span><span class="identifier">RemoveUnaryPlus</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">RemoveUnaryPlus</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child</span><span class="special">)</span> |
| <span class="special">></span> |
| <span class="comment">// Use proto::terminal<> and proto::nary_expr<></span> |
| <span class="comment">// both as grammars and as primitive transforms.</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">nary_expr</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">vararg</span><span class="special"><</span><span class="identifier">RemoveUnaryPlus</span><span class="special">></span> <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">literal</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="identifier">i</span><span class="special">(</span><span class="number">0</span><span class="special">);</span> |
| |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">display_expr</span><span class="special">(</span> |
| <span class="special">+</span><span class="identifier">i</span> <span class="special">-</span> <span class="special">+(</span><span class="identifier">i</span> <span class="special">-</span> <span class="special">+</span><span class="identifier">i</span><span class="special">)</span> |
| <span class="special">);</span> |
| |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">display_expr</span><span class="special">(</span> |
| <span class="identifier">RemoveUnaryPlus</span><span class="special">()(</span> <span class="special">+</span><span class="identifier">i</span> <span class="special">-</span> <span class="special">+(</span><span class="identifier">i</span> <span class="special">-</span> <span class="special">+</span><span class="identifier">i</span><span class="special">)</span> <span class="special">)</span> |
| <span class="special">);</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| The above code displays the following, which shows that unary plus nodes |
| have been stripped from the expression: |
| </p> |
| <pre class="programlisting">minus( |
| unary_plus( |
| terminal(0) |
| ) |
| , unary_plus( |
| minus( |
| terminal(0) |
| , unary_plus( |
| terminal(0) |
| ) |
| ) |
| ) |
| ) |
| minus( |
| terminal(0) |
| , minus( |
| terminal(0) |
| , terminal(0) |
| ) |
| ) |
| </pre> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_transformation.primitives"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.primitives" title="Building Custom Primitive Transforms">Building |
| Custom Primitive Transforms</a> |
| </h5></div></div></div> |
| <p> |
| In previous sections, we've seen how to compose larger transforms out |
| of smaller transforms using function types. The smaller transforms from |
| which larger transforms are composed are <span class="emphasis"><em>primitive transforms</em></span>, |
| and Proto provides a bunch of common ones such as <code class="computeroutput"><span class="identifier">_child0</span></code> |
| and <code class="computeroutput"><span class="identifier">_value</span></code>. In this section |
| we'll see how to author your own primitive transforms. |
| </p> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| There are a few reasons why you might want to write your own primitive |
| transforms. For instance, your transform may be complicated, and composing |
| it out of primitives becomes unwieldy. You might also need to work |
| around compiler bugs on legacy compilers that make composing transforms |
| using function types problematic. Finally, you might also decide to |
| define your own primitive transforms to improve compile times. Since |
| Proto can simply invoke a primitive transform directly without having |
| to process arguments or differentiate callable transforms from object |
| transforms, primitive transforms are more efficient. |
| </p></td></tr> |
| </table></div> |
| <p> |
| Primitive transforms inherit from <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">transform</span><span class="special"><></span></code> and have a nested <code class="computeroutput"><span class="identifier">impl</span><span class="special"><></span></code> |
| template that inherits from <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">transform_impl</span><span class="special"><></span></code>. For example, this is how Proto |
| defines the <code class="computeroutput"><span class="identifier">_child_c</span><span class="special"><</span><em class="replaceable"><code>N</code></em><span class="special">></span></code> |
| transform, which returns the <em class="replaceable"><code>N</code></em>-th child of |
| the current expression: |
| </p> |
| <pre class="programlisting"><span class="keyword">namespace</span> <span class="identifier">boost</span> <span class="special">{</span> <span class="keyword">namespace</span> <span class="identifier">proto</span> |
| <span class="special">{</span> |
| <span class="comment">// A primitive transform that returns N-th child</span> |
| <span class="comment">// of the current expression.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">N</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">_child_c</span> <span class="special">:</span> <span class="identifier">transform</span><span class="special"><</span><span class="identifier">_child_c</span><span class="special"><</span><span class="identifier">N</span><span class="special">></span> <span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">State</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Data</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">impl</span> <span class="special">:</span> <span class="identifier">transform_impl</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">State</span><span class="special">,</span> <span class="identifier">Data</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> |
| <span class="keyword">typename</span> <span class="identifier">result_of</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">N</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">result_type</span> <span class="keyword">operator</span> <span class="special">()(</span> |
| <span class="keyword">typename</span> <span class="identifier">impl</span><span class="special">::</span><span class="identifier">expr_param</span> <span class="identifier">expr</span> |
| <span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">impl</span><span class="special">::</span><span class="identifier">state_param</span> <span class="identifier">state</span> |
| <span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">impl</span><span class="special">::</span><span class="identifier">data_param</span> <span class="identifier">data</span> |
| <span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">child_c</span><span class="special"><</span><span class="identifier">N</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Note that _child_c<N> is callable, so that</span> |
| <span class="comment">// it can be used in callable transforms, as:</span> |
| <span class="comment">// _child_c<0>(_child_c<1>)</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">N</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">is_callable</span><span class="special"><</span><span class="identifier">_child_c</span><span class="special"><</span><span class="identifier">N</span><span class="special">></span> <span class="special">></span> |
| <span class="special">:</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">true_</span> |
| <span class="special">{};</span> |
| <span class="special">}}</span> |
| </pre> |
| <p> |
| The <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">transform</span><span class="special"><></span></code> |
| base class provides the <code class="computeroutput"><span class="keyword">operator</span><span class="special">()</span></code> overloads and the nested <code class="computeroutput"><span class="identifier">result</span><span class="special"><></span></code> |
| template that make your transform a valid function object. These are |
| implemented in terms of the nested <code class="computeroutput"><span class="identifier">impl</span><span class="special"><></span></code> template you define. |
| </p> |
| <p> |
| The <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">transform_impl</span><span class="special"><></span></code> |
| base class is a convenience. It provides some nested typedefs that are |
| generally useful. They are specified in the table below: |
| </p> |
| <div class="table"> |
| <a name="id2348076"></a><p class="title"><b>Table 16.11. proto::transform_impl<Expr, State, Data> typedefs</b></p> |
| <div class="table-contents"><table class="table" summary="proto::transform_impl<Expr, State, Data> typedefs"> |
| <colgroup> |
| <col> |
| <col> |
| </colgroup> |
| <thead><tr> |
| <th> |
| <p> |
| typedef |
| </p> |
| </th> |
| <th> |
| <p> |
| Equivalent To |
| </p> |
| </th> |
| </tr></thead> |
| <tbody> |
| <tr> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">expr</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="keyword">typename</span> <span class="identifier">remove_reference</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="identifier">type</span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">state</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="keyword">typename</span> <span class="identifier">remove_reference</span><span class="special"><</span><span class="identifier">State</span><span class="special">>::</span><span class="identifier">type</span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">data</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="keyword">typename</span> <span class="identifier">remove_reference</span><span class="special"><</span><span class="identifier">Data</span><span class="special">>::</span><span class="identifier">type</span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">expr_param</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="keyword">typename</span> <span class="identifier">add_reference</span><span class="special"><</span><span class="keyword">typename</span> |
| <span class="identifier">add_const</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="identifier">type</span><span class="special">>::</span><span class="identifier">type</span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">state_param</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="keyword">typename</span> <span class="identifier">add_reference</span><span class="special"><</span><span class="keyword">typename</span> |
| <span class="identifier">add_const</span><span class="special"><</span><span class="identifier">State</span><span class="special">>::</span><span class="identifier">type</span><span class="special">>::</span><span class="identifier">type</span></code> |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="identifier">data_param</span></code> |
| </p> |
| </td> |
| <td> |
| <p> |
| <code class="computeroutput"><span class="keyword">typename</span> <span class="identifier">add_reference</span><span class="special"><</span><span class="keyword">typename</span> |
| <span class="identifier">add_const</span><span class="special"><</span><span class="identifier">Data</span><span class="special">>::</span><span class="identifier">type</span><span class="special">>::</span><span class="identifier">type</span></code> |
| </p> |
| </td> |
| </tr> |
| </tbody> |
| </table></div> |
| </div> |
| <br class="table-break"><p> |
| You'll notice that <code class="computeroutput"><span class="identifier">_child_c</span><span class="special">::</span><span class="identifier">impl</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code> takes arguments of types <code class="computeroutput"><span class="identifier">expr_param</span></code>, <code class="computeroutput"><span class="identifier">state_param</span></code>, |
| and <code class="computeroutput"><span class="identifier">data_param</span></code>. The typedefs |
| make it easy to accept arguments by reference or const reference accordingly. |
| </p> |
| <p> |
| The only other interesting bit is the <code class="computeroutput"><span class="identifier">is_callable</span><span class="special"><></span></code> specialization, which will be |
| described in the <a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.is_callable" title="Making Your Transform Callable">next |
| section</a>. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h5 class="title"> |
| <a name="boost_proto.users_guide.back_end.expression_transformation.is_callable"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.is_callable" title="Making Your Transform Callable">Making |
| Your Transform Callable</a> |
| </h5></div></div></div> |
| <p> |
| Transforms are typically of the form <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> <span class="identifier">Something</span><span class="special">,</span> <span class="identifier">R</span><span class="special">(</span><span class="identifier">A0</span><span class="special">,</span><span class="identifier">A1</span><span class="special">,...)</span> <span class="special">></span></code>. |
| The question is whether <code class="computeroutput"><span class="identifier">R</span></code> |
| represents a function to call or an object to construct, and the answer |
| determines how <code class="computeroutput"><a class="link" href="../boost/proto/when.html" title="Struct template when">proto::when<></a></code> evaluates the transform. |
| <code class="computeroutput"><a class="link" href="../boost/proto/when.html" title="Struct template when">proto::when<></a></code> uses the <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">is_callable</span><span class="special"><></span></code> |
| trait to disambiguate between the two. Proto does its best to guess whether |
| a type is callable or not, but it doesn't always get it right. It's best |
| to know the rules Proto uses, so that you know when you need to be more |
| explicit. |
| </p> |
| <p> |
| For most types <code class="computeroutput"><span class="identifier">R</span></code>, <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">is_callable</span><span class="special"><</span><span class="identifier">R</span><span class="special">></span></code> |
| checks for inheritance from <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable</span></code>. |
| However, if the type <code class="computeroutput"><span class="identifier">R</span></code> |
| is a template specialization, Proto assumes that it is <span class="emphasis"><em>not</em></span> |
| callable <span class="emphasis"><em>even if the template inherits from <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable</span></code></em></span>. |
| We'll see why in a minute. Consider the following erroneous callable |
| object: |
| </p> |
| <pre class="programlisting"><span class="comment">// Proto can't tell this defines something callable!</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">times2</span> <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable</span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="identifier">T</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">T</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">T</span> <span class="identifier">i</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">i</span> <span class="special">*</span> <span class="number">2</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// ERROR! This is not going to multiply the int by 2:</span> |
| <span class="keyword">struct</span> <span class="identifier">IntTimes2</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">times2</span><span class="special"><</span><span class="keyword">int</span><span class="special">>(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">)</span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| The problem is that Proto doesn't know that <code class="computeroutput"><span class="identifier">times2</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span></code> is callable, so rather that invoking |
| the <code class="computeroutput"><span class="identifier">times2</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span></code> |
| function object, Proto will try to construct a <code class="computeroutput"><span class="identifier">times2</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span></code> object and initialize it will an |
| <code class="computeroutput"><span class="keyword">int</span></code>. That will not compile. |
| </p> |
| <div class="note"><table border="0" summary="Note"> |
| <tr> |
| <td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td> |
| <th align="left">Note</th> |
| </tr> |
| <tr><td align="left" valign="top"><p> |
| Why can't Proto tell that <code class="computeroutput"><span class="identifier">times2</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span></code> is callable? After all, it inherits |
| from <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable</span></code>, and that is detectable, |
| right? The problem is that merely asking whether some type <code class="computeroutput"><span class="identifier">X</span><span class="special"><</span><span class="identifier">Y</span><span class="special">></span></code> |
| inherits from <code class="computeroutput"><span class="identifier">callable</span></code> |
| will cause the template <code class="computeroutput"><span class="identifier">X</span><span class="special"><</span><span class="identifier">Y</span><span class="special">></span></code> to be instantiated. That's a problem |
| for a type like <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">_value</span><span class="special">(</span><span class="identifier">_child1</span><span class="special">)></span></code>. <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><></span></code> will not suffer to be instantiated |
| with <code class="computeroutput"><span class="identifier">_value</span><span class="special">(</span><span class="identifier">_child1</span><span class="special">)</span></code> |
| as a template parameter. Since merely asking the question will sometimes |
| result in a hard error, Proto can't ask; it has to assume that <code class="computeroutput"><span class="identifier">X</span><span class="special"><</span><span class="identifier">Y</span><span class="special">></span></code> |
| represents an object to construct and not a function to call. |
| </p></td></tr> |
| </table></div> |
| <p> |
| There are a couple of solutions to the <code class="computeroutput"><span class="identifier">times2</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span></code> problem. One solution is to wrap |
| the transform in <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">call</span><span class="special"><></span></code>. This forces Proto to treat |
| <code class="computeroutput"><span class="identifier">times2</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span></code> |
| as callable: |
| </p> |
| <pre class="programlisting"><span class="comment">// OK, calls times2<int></span> |
| <span class="keyword">struct</span> <span class="identifier">IntTimes2</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">call</span><span class="special"><</span><span class="identifier">times2</span><span class="special"><</span><span class="keyword">int</span><span class="special">>(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">)></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| This can be a bit of a pain, because we need to wrap every use of <code class="computeroutput"><span class="identifier">times2</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span></code>, |
| which can be tedious and error prone, and makes our grammar cluttered |
| and harder to read. |
| </p> |
| <p> |
| Another solution is to specialize <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">is_callable</span><span class="special"><></span></code> on our <code class="computeroutput"><span class="identifier">times2</span><span class="special"><></span></code> template: |
| </p> |
| <pre class="programlisting"><span class="keyword">namespace</span> <span class="identifier">boost</span> <span class="special">{</span> <span class="keyword">namespace</span> <span class="identifier">proto</span> |
| <span class="special">{</span> |
| <span class="comment">// Tell Proto that times2<> is callable</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">is_callable</span><span class="special"><</span><span class="identifier">times2</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span> <span class="special">></span> |
| <span class="special">:</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">true_</span> |
| <span class="special">{};</span> |
| <span class="special">}}</span> |
| |
| <span class="comment">// OK, times2<> is callable</span> |
| <span class="keyword">struct</span> <span class="identifier">IntTimes2</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">times2</span><span class="special"><</span><span class="keyword">int</span><span class="special">>(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">)</span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| This is better, but still a pain because of the need to open Proto's |
| namespace. |
| </p> |
| <p> |
| You could simply make sure that the callable type is not a template specialization. |
| Consider the following: |
| </p> |
| <pre class="programlisting"><span class="comment">// No longer a template specialization!</span> |
| <span class="keyword">struct</span> <span class="identifier">times2int</span> <span class="special">:</span> <span class="identifier">times2</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="special">{};</span> |
| |
| <span class="comment">// OK, times2int is callable</span> |
| <span class="keyword">struct</span> <span class="identifier">IntTimes2</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">times2int</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">)</span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| This works because now Proto can tell that <code class="computeroutput"><span class="identifier">times2int</span></code> |
| inherits (indirectly) from <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable</span></code>. |
| Any non-template types can be safely checked for inheritance because, |
| as they are not templates, there is no worry about instantiation errors. |
| </p> |
| <p> |
| There is one last way to tell Proto that <code class="computeroutput"><span class="identifier">times2</span><span class="special"><></span></code> is callable. You could add an |
| extra dummy template parameter that defaults to <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable</span></code>: |
| </p> |
| <pre class="programlisting"><span class="comment">// Proto will recognize this as callable</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Callable</span> <span class="special">=</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">times2</span> <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable</span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="identifier">T</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">T</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">T</span> <span class="identifier">i</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">i</span> <span class="special">*</span> <span class="number">2</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// OK, this works!</span> |
| <span class="keyword">struct</span> <span class="identifier">IntTimes2</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">times2</span><span class="special"><</span><span class="keyword">int</span><span class="special">>(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">)</span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| </pre> |
| <p> |
| Note that in addition to the extra template parameter, <code class="computeroutput"><span class="identifier">times2</span><span class="special"><></span></code> |
| still inherits from <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable</span></code>. |
| That's not necessary in this example but it is good style because any |
| types derived from <code class="computeroutput"><span class="identifier">times2</span><span class="special"><></span></code> (as <code class="computeroutput"><span class="identifier">times2int</span></code> |
| defined above) will still be considered callable. |
| </p> |
| </div> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="boost_proto.users_guide.examples"></a><a class="link" href="users_guide.html#boost_proto.users_guide.examples" title="Examples">Examples</a> |
| </h3></div></div></div> |
| <div class="toc"><dl> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.examples.hello_world">Hello |
| World: Building an Expression Template and Evaluating It</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.examples.calc1">Calc1: Defining |
| an Evaluation Context</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.examples.calc2">Calc2: Adding |
| Members Using <code class="literal">proto::extends<></code></a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.examples.calc3">Calc3: Defining |
| a Simple Transform</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.examples.lazy_vector">Lazy |
| Vector: Controlling Operator Overloads</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.examples.rgb">RGB: Type Manipulations |
| with Proto Transforms</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.examples.tarray">TArray: A |
| Simple Linear Algebra Library</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.examples.vec3">Vec3: Computing |
| With Transforms and Contexts</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.examples.vector">Vector: Adapting |
| a Non-Proto Terminal Type</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.examples.mixed">Mixed: Adapting |
| Several Non-Proto Terminal Types</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.examples.map_assign">Map Assign: |
| An Intermediate Transform</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.examples.future_group">Future |
| Group: A More Advanced Transform</a></span></dt> |
| <dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.examples.lambda">Lambda: A |
| Simple Lambda Library with Proto</a></span></dt> |
| </dl></div> |
| <p> |
| A code example is worth a thousand words ... |
| </p> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.examples.hello_world"></a><a class="link" href="users_guide.html#boost_proto.users_guide.examples.hello_world" title="Hello World: Building an Expression Template and Evaluating It">Hello |
| World: Building an Expression Template and Evaluating It</a> |
| </h4></div></div></div> |
| <p> |
| A trivial example which builds and expression template and evaluates it. |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="comment">////////////////////////////////////////////////////////////////////</span> |
| <span class="comment">// Copyright 2008 Eric Niebler. Distributed under the Boost</span> |
| <span class="comment">// Software License, Version 1.0. (See accompanying file</span> |
| <span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span> |
| |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">context</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="comment">// This #include is only needed for compilers that use typeof emulation:</span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">typeof</span><span class="special">/</span><span class="identifier">std</span><span class="special">/</span><span class="identifier">ostream</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="keyword">namespace</span> <span class="identifier">proto</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">;</span> |
| |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span> <span class="special">>::</span><span class="identifier">type</span> <span class="identifier">cout_</span> <span class="special">=</span> <span class="special">{</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Expr</span> <span class="special">></span> |
| <span class="keyword">void</span> <span class="identifier">evaluate</span><span class="special">(</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">expr</span> <span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">default_context</span> <span class="identifier">ctx</span><span class="special">;</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="identifier">evaluate</span><span class="special">(</span> <span class="identifier">cout_</span> <span class="special"><<</span> <span class="string">"hello"</span> <span class="special"><<</span> <span class="char">','</span> <span class="special"><<</span> <span class="string">" world"</span> <span class="special">);</span> |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.examples.calc1"></a><a class="link" href="users_guide.html#boost_proto.users_guide.examples.calc1" title="Calc1: Defining an Evaluation Context">Calc1: Defining |
| an Evaluation Context</a> |
| </h4></div></div></div> |
| <p> |
| A simple example that builds a miniature domain-specific embedded language |
| for lazy arithmetic expressions, with TR1 bind-style argument placeholders. |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="comment">// Copyright 2008 Eric Niebler. Distributed under the Boost</span> |
| <span class="comment">// Software License, Version 1.0. (See accompanying file</span> |
| <span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span> |
| <span class="comment">//</span> |
| <span class="comment">// This is a simple example of how to build an arithmetic expression</span> |
| <span class="comment">// evaluator with placeholders.</span> |
| |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">context</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="keyword">namespace</span> <span class="identifier">proto</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">;</span> |
| <span class="keyword">using</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span><span class="special">;</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">I</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">placeholder</span> <span class="special">{};</span> |
| |
| <span class="comment">// Define some placeholders</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span> <span class="number">1</span> <span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">_1</span> <span class="special">=</span> <span class="special">{{}};</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span> <span class="number">2</span> <span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="identifier">_2</span> <span class="special">=</span> <span class="special">{{}};</span> |
| |
| <span class="comment">// Define a calculator context, for evaluating arithmetic expressions</span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_context</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable_context</span><span class="special"><</span> <span class="identifier">calculator_context</span> <span class="keyword">const</span> <span class="special">></span> |
| <span class="special">{</span> |
| <span class="comment">// The values bound to the placeholders</span> |
| <span class="keyword">double</span> <span class="identifier">d</span><span class="special">[</span><span class="number">2</span><span class="special">];</span> |
| |
| <span class="comment">// The result of evaluating arithmetic expressions</span> |
| <span class="keyword">typedef</span> <span class="keyword">double</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="keyword">explicit</span> <span class="identifier">calculator_context</span><span class="special">(</span><span class="keyword">double</span> <span class="identifier">d1</span> <span class="special">=</span> <span class="number">0.</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">d2</span> <span class="special">=</span> <span class="number">0.</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">d</span><span class="special">[</span><span class="number">0</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">d1</span><span class="special">;</span> |
| <span class="identifier">d</span><span class="special">[</span><span class="number">1</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">d2</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="comment">// Handle the evaluation of the placeholder terminals</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">I</span><span class="special">></span> |
| <span class="keyword">double</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">,</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="identifier">I</span><span class="special">>)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">d</span><span class="special">[</span> <span class="identifier">I</span> <span class="special">-</span> <span class="number">1</span> <span class="special">];</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">double</span> <span class="identifier">evaluate</span><span class="special">(</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">d1</span> <span class="special">=</span> <span class="number">0.</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">d2</span> <span class="special">=</span> <span class="number">0.</span> <span class="special">)</span> |
| <span class="special">{</span> |
| <span class="comment">// Create a calculator context with d1 and d2 substituted for _1 and _2</span> |
| <span class="identifier">calculator_context</span> <span class="keyword">const</span> <span class="identifier">ctx</span><span class="special">(</span><span class="identifier">d1</span><span class="special">,</span> <span class="identifier">d2</span><span class="special">);</span> |
| |
| <span class="comment">// Evaluate the calculator expression with the calculator_context</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="comment">// Displays "5"</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">evaluate</span><span class="special">(</span> <span class="identifier">_1</span> <span class="special">+</span> <span class="number">2.0</span><span class="special">,</span> <span class="number">3.0</span> <span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="comment">// Displays "6"</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">evaluate</span><span class="special">(</span> <span class="identifier">_1</span> <span class="special">*</span> <span class="identifier">_2</span><span class="special">,</span> <span class="number">3.0</span><span class="special">,</span> <span class="number">2.0</span> <span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="comment">// Displays "0.5"</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">evaluate</span><span class="special">(</span> <span class="special">(</span><span class="identifier">_1</span> <span class="special">-</span> <span class="identifier">_2</span><span class="special">)</span> <span class="special">/</span> <span class="identifier">_2</span><span class="special">,</span> <span class="number">3.0</span><span class="special">,</span> <span class="number">2.0</span> <span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.examples.calc2"></a><a class="link" href="users_guide.html#boost_proto.users_guide.examples.calc2" title="Calc2: Adding Members Using proto::extends<>">Calc2: Adding |
| Members Using <code class="literal">proto::extends<></code></a> |
| </h4></div></div></div> |
| <p> |
| An extension of the Calc1 example that uses <code class="computeroutput"><a class="link" href="../boost/proto/extends.html" title="Struct template extends">proto::extends<></a></code> |
| to make calculator expressions valid function objects that can be used |
| with STL algorithms. |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="comment">// Copyright 2008 Eric Niebler. Distributed under the Boost</span> |
| <span class="comment">// Software License, Version 1.0. (See accompanying file</span> |
| <span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span> |
| <span class="comment">//</span> |
| <span class="comment">// This example enhances the simple arithmetic expression evaluator</span> |
| <span class="comment">// in calc1.cpp by using proto::extends to make arithmetic</span> |
| <span class="comment">// expressions immediately evaluable with operator (), a-la a</span> |
| <span class="comment">// function object</span> |
| |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">context</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="keyword">namespace</span> <span class="identifier">proto</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">;</span> |
| <span class="keyword">using</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span><span class="special">;</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_expression</span><span class="special">;</span> |
| |
| <span class="comment">// Tell proto how to generate expressions in the calculator_domain</span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_domain</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">generator</span><span class="special"><</span><span class="identifier">calculator_expression</span><span class="special">></span> <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Will be used to define the placeholders _1 and _2</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">I</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">placeholder</span> <span class="special">{};</span> |
| |
| <span class="comment">// Define a calculator context, for evaluating arithmetic expressions</span> |
| <span class="comment">// (This is as before, in calc1.cpp)</span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_context</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable_context</span><span class="special"><</span> <span class="identifier">calculator_context</span> <span class="keyword">const</span> <span class="special">></span> |
| <span class="special">{</span> |
| <span class="comment">// The values bound to the placeholders</span> |
| <span class="keyword">double</span> <span class="identifier">d</span><span class="special">[</span><span class="number">2</span><span class="special">];</span> |
| |
| <span class="comment">// The result of evaluating arithmetic expressions</span> |
| <span class="keyword">typedef</span> <span class="keyword">double</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="keyword">explicit</span> <span class="identifier">calculator_context</span><span class="special">(</span><span class="keyword">double</span> <span class="identifier">d1</span> <span class="special">=</span> <span class="number">0.</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">d2</span> <span class="special">=</span> <span class="number">0.</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">d</span><span class="special">[</span><span class="number">0</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">d1</span><span class="special">;</span> |
| <span class="identifier">d</span><span class="special">[</span><span class="number">1</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">d2</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="comment">// Handle the evaluation of the placeholder terminals</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">I</span><span class="special">></span> |
| <span class="keyword">double</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">,</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="identifier">I</span><span class="special">>)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">d</span><span class="special">[</span> <span class="identifier">I</span> <span class="special">-</span> <span class="number">1</span> <span class="special">];</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Wrap all calculator expressions in this type, which defines</span> |
| <span class="comment">// operator () to evaluate the expression.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_expression</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">calculator_expression</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>,</span> <span class="identifier">calculator_domain</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">explicit</span> <span class="identifier">calculator_expression</span><span class="special">(</span><span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span> <span class="special">=</span> <span class="identifier">Expr</span><span class="special">())</span> |
| <span class="special">:</span> <span class="identifier">calculator_expression</span><span class="special">::</span><span class="identifier">proto_extends</span><span class="special">(</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="identifier">BOOST_PROTO_EXTENDS_USING_ASSIGN</span><span class="special">(</span><span class="identifier">calculator_expression</span><span class="special">)</span> |
| |
| <span class="comment">// Override operator () to evaluate the expression</span> |
| <span class="keyword">double</span> <span class="keyword">operator</span> <span class="special">()()</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">calculator_context</span> <span class="keyword">const</span> <span class="identifier">ctx</span><span class="special">;</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">double</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="keyword">double</span> <span class="identifier">d1</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">calculator_context</span> <span class="keyword">const</span> <span class="identifier">ctx</span><span class="special">(</span><span class="identifier">d1</span><span class="special">);</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">double</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="keyword">double</span> <span class="identifier">d1</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">d2</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">calculator_context</span> <span class="keyword">const</span> <span class="identifier">ctx</span><span class="special">(</span><span class="identifier">d1</span><span class="special">,</span> <span class="identifier">d2</span><span class="special">);</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Define some placeholders (notice they're wrapped in calculator_expression<>)</span> |
| <span class="identifier">calculator_expression</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span> <span class="number">1</span> <span class="special">></span> <span class="special">>::</span><span class="identifier">type</span><span class="special">></span> <span class="keyword">const</span> <span class="identifier">_1</span><span class="special">;</span> |
| <span class="identifier">calculator_expression</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span> <span class="number">2</span> <span class="special">></span> <span class="special">>::</span><span class="identifier">type</span><span class="special">></span> <span class="keyword">const</span> <span class="identifier">_2</span><span class="special">;</span> |
| |
| <span class="comment">// Now, our arithmetic expressions are immediately executable function objects:</span> |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="comment">// Displays "5"</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="special">(</span><span class="identifier">_1</span> <span class="special">+</span> <span class="number">2.0</span><span class="special">)(</span> <span class="number">3.0</span> <span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="comment">// Displays "6"</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="special">(</span> <span class="identifier">_1</span> <span class="special">*</span> <span class="identifier">_2</span> <span class="special">)(</span> <span class="number">3.0</span><span class="special">,</span> <span class="number">2.0</span> <span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="comment">// Displays "0.5"</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="special">(</span> <span class="special">(</span><span class="identifier">_1</span> <span class="special">-</span> <span class="identifier">_2</span><span class="special">)</span> <span class="special">/</span> <span class="identifier">_2</span> <span class="special">)(</span> <span class="number">3.0</span><span class="special">,</span> <span class="number">2.0</span> <span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.examples.calc3"></a><a class="link" href="users_guide.html#boost_proto.users_guide.examples.calc3" title="Calc3: Defining a Simple Transform">Calc3: Defining |
| a Simple Transform</a> |
| </h4></div></div></div> |
| <p> |
| An extension of the Calc2 example that uses a Proto transform to calculate |
| the arity of a calculator expression and statically assert that the correct |
| number of arguments are passed. |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="comment">// Copyright 2008 Eric Niebler. Distributed under the Boost</span> |
| <span class="comment">// Software License, Version 1.0. (See accompanying file</span> |
| <span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span> |
| <span class="comment">//</span> |
| <span class="comment">// This example enhances the arithmetic expression evaluator</span> |
| <span class="comment">// in calc2.cpp by using a proto transform to calculate the</span> |
| <span class="comment">// number of arguments an expression requires and using a</span> |
| <span class="comment">// compile-time assert to guarantee that the right number of</span> |
| <span class="comment">// arguments are actually specified.</span> |
| |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mpl</span><span class="special">/</span><span class="keyword">int</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mpl</span><span class="special">/</span><span class="identifier">assert</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mpl</span><span class="special">/</span><span class="identifier">min_max</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">context</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">transform</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="keyword">namespace</span> <span class="identifier">mpl</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">mpl</span><span class="special">;</span> |
| <span class="keyword">namespace</span> <span class="identifier">proto</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">;</span> |
| <span class="keyword">using</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span><span class="special">;</span> |
| |
| <span class="comment">// Will be used to define the placeholders _1 and _2</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">I</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">placeholder</span> <span class="special">:</span> <span class="identifier">I</span> <span class="special">{};</span> |
| |
| <span class="comment">// This grammar basically says that a calculator expression is one of:</span> |
| <span class="comment">// - A placeholder terminal</span> |
| <span class="comment">// - Some other terminal</span> |
| <span class="comment">// - Some non-terminal whose children are calculator expressions</span> |
| <span class="comment">// In addition, it has transforms that say how to calculate the</span> |
| <span class="comment">// expression arity for each of the three cases.</span> |
| <span class="keyword">struct</span> <span class="identifier">CalculatorGrammar</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| |
| <span class="comment">// placeholders have a non-zero arity ...</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> <span class="special">>,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span> <span class="special">></span> |
| |
| <span class="comment">// Any other terminals have arity 0 ...</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">_</span><span class="special">>,</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">int_</span><span class="special"><</span><span class="number">0</span><span class="special">>()</span> <span class="special">></span> |
| |
| <span class="comment">// For any non-terminals, find the arity of the children and</span> |
| <span class="comment">// take the maximum. This is recursive.</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">nary_expr</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">vararg</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">fold</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">int_</span><span class="special"><</span><span class="number">0</span><span class="special">>(),</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">max</span><span class="special"><</span><span class="identifier">CalculatorGrammar</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span><span class="special">>()</span> <span class="special">></span> <span class="special">></span> |
| |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Simple wrapper for calculating a calculator expression's arity.</span> |
| <span class="comment">// It specifies mpl::int_<0> as the initial state. The data, which</span> |
| <span class="comment">// is not used, is mpl::void_.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_arity</span> |
| <span class="special">:</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">result_of</span><span class="special"><</span><span class="identifier">CalculatorGrammar</span><span class="special">(</span><span class="identifier">Expr</span><span class="special">)></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_expression</span><span class="special">;</span> |
| |
| <span class="comment">// Tell proto how to generate expressions in the calculator_domain</span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_domain</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">generator</span><span class="special"><</span><span class="identifier">calculator_expression</span><span class="special">></span> <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Define a calculator context, for evaluating arithmetic expressions</span> |
| <span class="comment">// (This is as before, in calc1.cpp and calc2.cpp)</span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_context</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable_context</span><span class="special"><</span> <span class="identifier">calculator_context</span> <span class="keyword">const</span> <span class="special">></span> |
| <span class="special">{</span> |
| <span class="comment">// The values bound to the placeholders</span> |
| <span class="keyword">double</span> <span class="identifier">d</span><span class="special">[</span><span class="number">2</span><span class="special">];</span> |
| |
| <span class="comment">// The result of evaluating arithmetic expressions</span> |
| <span class="keyword">typedef</span> <span class="keyword">double</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="keyword">explicit</span> <span class="identifier">calculator_context</span><span class="special">(</span><span class="keyword">double</span> <span class="identifier">d1</span> <span class="special">=</span> <span class="number">0.</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">d2</span> <span class="special">=</span> <span class="number">0.</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">d</span><span class="special">[</span><span class="number">0</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">d1</span><span class="special">;</span> |
| <span class="identifier">d</span><span class="special">[</span><span class="number">1</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">d2</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="comment">// Handle the evaluation of the placeholder terminals</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">I</span><span class="special">></span> |
| <span class="keyword">double</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">,</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="identifier">I</span><span class="special">>)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">d</span><span class="special">[</span> <span class="identifier">I</span><span class="special">()</span> <span class="special">-</span> <span class="number">1</span> <span class="special">];</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Wrap all calculator expressions in this type, which defines</span> |
| <span class="comment">// operator () to evaluate the expression.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">calculator_expression</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">calculator_expression</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>,</span> <span class="identifier">calculator_domain</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">calculator_expression</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>,</span> <span class="identifier">calculator_domain</span><span class="special">></span> |
| <span class="identifier">base_type</span><span class="special">;</span> |
| |
| <span class="keyword">explicit</span> <span class="identifier">calculator_expression</span><span class="special">(</span><span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span> <span class="special">=</span> <span class="identifier">Expr</span><span class="special">())</span> |
| <span class="special">:</span> <span class="identifier">base_type</span><span class="special">(</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="identifier">BOOST_PROTO_EXTENDS_USING_ASSIGN</span><span class="special">(</span><span class="identifier">calculator_expression</span><span class="special">)</span> |
| |
| <span class="comment">// Override operator () to evaluate the expression</span> |
| <span class="keyword">double</span> <span class="keyword">operator</span> <span class="special">()()</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="comment">// Assert that the expression has arity 0</span> |
| <span class="identifier">BOOST_MPL_ASSERT_RELATION</span><span class="special">(</span><span class="number">0</span><span class="special">,</span> <span class="special">==,</span> <span class="identifier">calculator_arity</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="identifier">type</span><span class="special">::</span><span class="identifier">value</span><span class="special">);</span> |
| <span class="identifier">calculator_context</span> <span class="keyword">const</span> <span class="identifier">ctx</span><span class="special">;</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">double</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="keyword">double</span> <span class="identifier">d1</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="comment">// Assert that the expression has arity 1</span> |
| <span class="identifier">BOOST_MPL_ASSERT_RELATION</span><span class="special">(</span><span class="number">1</span><span class="special">,</span> <span class="special">==,</span> <span class="identifier">calculator_arity</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="identifier">type</span><span class="special">::</span><span class="identifier">value</span><span class="special">);</span> |
| <span class="identifier">calculator_context</span> <span class="keyword">const</span> <span class="identifier">ctx</span><span class="special">(</span><span class="identifier">d1</span><span class="special">);</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">double</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="keyword">double</span> <span class="identifier">d1</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">d2</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="comment">// Assert that the expression has arity 2</span> |
| <span class="identifier">BOOST_MPL_ASSERT_RELATION</span><span class="special">(</span><span class="number">2</span><span class="special">,</span> <span class="special">==,</span> <span class="identifier">calculator_arity</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="identifier">type</span><span class="special">::</span><span class="identifier">value</span><span class="special">);</span> |
| <span class="identifier">calculator_context</span> <span class="keyword">const</span> <span class="identifier">ctx</span><span class="special">(</span><span class="identifier">d1</span><span class="special">,</span> <span class="identifier">d2</span><span class="special">);</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Define some placeholders (notice they're wrapped in calculator_expression<>)</span> |
| <span class="identifier">calculator_expression</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">int_</span><span class="special"><</span><span class="number">1</span><span class="special">></span> <span class="special">></span> <span class="special">>::</span><span class="identifier">type</span><span class="special">></span> <span class="keyword">const</span> <span class="identifier">_1</span><span class="special">;</span> |
| <span class="identifier">calculator_expression</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">int_</span><span class="special"><</span><span class="number">2</span><span class="special">></span> <span class="special">></span> <span class="special">>::</span><span class="identifier">type</span><span class="special">></span> <span class="keyword">const</span> <span class="identifier">_2</span><span class="special">;</span> |
| |
| <span class="comment">// Now, our arithmetic expressions are immediately executable function objects:</span> |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="comment">// Displays "5"</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="special">(</span><span class="identifier">_1</span> <span class="special">+</span> <span class="number">2.0</span><span class="special">)(</span> <span class="number">3.0</span> <span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="comment">// Displays "6"</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="special">(</span> <span class="identifier">_1</span> <span class="special">*</span> <span class="identifier">_2</span> <span class="special">)(</span> <span class="number">3.0</span><span class="special">,</span> <span class="number">2.0</span> <span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="comment">// Displays "0.5"</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="special">(</span> <span class="special">(</span><span class="identifier">_1</span> <span class="special">-</span> <span class="identifier">_2</span><span class="special">)</span> <span class="special">/</span> <span class="identifier">_2</span> <span class="special">)(</span> <span class="number">3.0</span><span class="special">,</span> <span class="number">2.0</span> <span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="comment">// This won't compile because the arity of the</span> |
| <span class="comment">// expression doesn't match the number of arguments</span> |
| <span class="comment">// ( (_1 - _2) / _2 )( 3.0 );</span> |
| |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.examples.lazy_vector"></a><a class="link" href="users_guide.html#boost_proto.users_guide.examples.lazy_vector" title="Lazy Vector: Controlling Operator Overloads">Lazy |
| Vector: Controlling Operator Overloads</a> |
| </h4></div></div></div> |
| <p> |
| This example constructs a mini-library for linear algebra, using expression |
| templates to eliminate the need for temporaries when adding vectors of |
| numbers. |
| </p> |
| <p> |
| This example uses a domain with a grammar to prune the set of overloaded |
| operators. Only those operators that produce valid lazy vector expressions |
| are allowed. |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="comment">///////////////////////////////////////////////////////////////////////////////</span> |
| <span class="comment">// Copyright 2008 Eric Niebler. Distributed under the Boost</span> |
| <span class="comment">// Software License, Version 1.0. (See accompanying file</span> |
| <span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span> |
| <span class="comment">//</span> |
| <span class="comment">// This example constructs a mini-library for linear algebra, using</span> |
| <span class="comment">// expression templates to eliminate the need for temporaries when</span> |
| <span class="comment">// adding vectors of numbers.</span> |
| <span class="comment">//</span> |
| <span class="comment">// This example uses a domain with a grammar to prune the set</span> |
| <span class="comment">// of overloaded operators. Only those operators that produce</span> |
| <span class="comment">// valid lazy vector expressions are allowed.</span> |
| |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">vector</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mpl</span><span class="special">/</span><span class="keyword">int</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">context</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="keyword">namespace</span> <span class="identifier">mpl</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">mpl</span><span class="special">;</span> |
| <span class="keyword">namespace</span> <span class="identifier">proto</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">;</span> |
| <span class="keyword">using</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span><span class="special">;</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">lazy_vector_expr</span><span class="special">;</span> |
| |
| <span class="comment">// This grammar describes which lazy vector expressions</span> |
| <span class="comment">// are allowed; namely, vector terminals and addition</span> |
| <span class="comment">// and subtraction of lazy vector expressions.</span> |
| <span class="keyword">struct</span> <span class="identifier">LazyVectorGrammar</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span> <span class="identifier">LazyVectorGrammar</span><span class="special">,</span> <span class="identifier">LazyVectorGrammar</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">minus</span><span class="special"><</span> <span class="identifier">LazyVectorGrammar</span><span class="special">,</span> <span class="identifier">LazyVectorGrammar</span> <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Tell proto that in the lazy_vector_domain, all</span> |
| <span class="comment">// expressions should be wrapped in laxy_vector_expr<></span> |
| <span class="comment">// and must conform to the lazy vector grammar.</span> |
| <span class="keyword">struct</span> <span class="identifier">lazy_vector_domain</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">generator</span><span class="special"><</span><span class="identifier">lazy_vector_expr</span><span class="special">>,</span> <span class="identifier">LazyVectorGrammar</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Here is an evaluation context that indexes into a lazy vector</span> |
| <span class="comment">// expression, and combines the result.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Size</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">lazy_subscript_context</span> |
| <span class="special">{</span> |
| <span class="identifier">lazy_subscript_context</span><span class="special">(</span><span class="identifier">Size</span> <span class="identifier">subscript</span><span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">subscript_</span><span class="special">(</span><span class="identifier">subscript</span><span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="comment">// Use default_eval for all the operations ...</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Tag</span> <span class="special">=</span> <span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">::</span><span class="identifier">proto_tag</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">default_eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">lazy_subscript_context</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// ... except for terminals, which we index with our subscript</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">value</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="identifier">type</span><span class="special">::</span><span class="identifier">value_type</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">result_type</span> <span class="keyword">operator</span> <span class="special">()(</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">expr</span><span class="special">,</span> <span class="identifier">lazy_subscript_context</span> <span class="special">&</span> <span class="identifier">ctx</span> <span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">value</span><span class="special">(</span> <span class="identifier">expr</span> <span class="special">)[</span> <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">subscript_</span> <span class="special">];</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="identifier">Size</span> <span class="identifier">subscript_</span><span class="special">;</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Here is the domain-specific expression wrapper, which overrides</span> |
| <span class="comment">// operator [] to evaluate the expression using the lazy_subscript_context.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">lazy_vector_expr</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">lazy_vector_expr</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>,</span> <span class="identifier">lazy_vector_domain</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="identifier">lazy_vector_expr</span><span class="special">(</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">expr</span> <span class="special">=</span> <span class="identifier">Expr</span><span class="special">()</span> <span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">lazy_vector_expr</span><span class="special">::</span><span class="identifier">proto_extends</span><span class="special">(</span> <span class="identifier">expr</span> <span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="comment">// Use the lazy_subscript_context<> to implement subscripting</span> |
| <span class="comment">// of a lazy vector expression tree.</span> |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Size</span> <span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">eval</span><span class="special"><</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">lazy_subscript_context</span><span class="special"><</span><span class="identifier">Size</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> |
| <span class="keyword">operator</span> <span class="special">[](</span> <span class="identifier">Size</span> <span class="identifier">subscript</span> <span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">lazy_subscript_context</span><span class="special"><</span><span class="identifier">Size</span><span class="special">></span> <span class="identifier">ctx</span><span class="special">(</span><span class="identifier">subscript</span><span class="special">);</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Here is our lazy_vector terminal, implemented in terms of lazy_vector_expr</span> |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">T</span> <span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">lazy_vector</span> |
| <span class="special">:</span> <span class="identifier">lazy_vector_expr</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> <span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span> <span class="special">>::</span><span class="identifier">type</span> <span class="identifier">expr_type</span><span class="special">;</span> |
| |
| <span class="identifier">lazy_vector</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">size</span> <span class="special">=</span> <span class="number">0</span><span class="special">,</span> <span class="identifier">T</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">value</span> <span class="special">=</span> <span class="identifier">T</span><span class="special">()</span> <span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">lazy_vector_expr</span><span class="special"><</span><span class="identifier">expr_type</span><span class="special">>(</span> <span class="identifier">expr_type</span><span class="special">::</span><span class="identifier">make</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">T</span><span class="special">>(</span> <span class="identifier">size</span><span class="special">,</span> <span class="identifier">value</span> <span class="special">)</span> <span class="special">)</span> <span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="comment">// Here we define a += operator for lazy vector terminals that</span> |
| <span class="comment">// takes a lazy vector expression and indexes it. expr[i] here</span> |
| <span class="comment">// uses lazy_subscript_context<> under the covers.</span> |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Expr</span> <span class="special">></span> |
| <span class="identifier">lazy_vector</span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">+=</span> <span class="special">(</span><span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">size</span> <span class="special">=</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">value</span><span class="special">(*</span><span class="keyword">this</span><span class="special">).</span><span class="identifier">size</span><span class="special">();</span> |
| <span class="keyword">for</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="identifier">i</span> <span class="special"><</span> <span class="identifier">size</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">value</span><span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="identifier">i</span><span class="special">]</span> <span class="special">+=</span> <span class="identifier">expr</span><span class="special">[</span><span class="identifier">i</span><span class="special">];</span> |
| <span class="special">}</span> |
| <span class="keyword">return</span> <span class="special">*</span><span class="keyword">this</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="comment">// lazy_vectors with 4 elements each.</span> |
| <span class="identifier">lazy_vector</span><span class="special"><</span> <span class="keyword">double</span> <span class="special">></span> <span class="identifier">v1</span><span class="special">(</span> <span class="number">4</span><span class="special">,</span> <span class="number">1.0</span> <span class="special">),</span> <span class="identifier">v2</span><span class="special">(</span> <span class="number">4</span><span class="special">,</span> <span class="number">2.0</span> <span class="special">),</span> <span class="identifier">v3</span><span class="special">(</span> <span class="number">4</span><span class="special">,</span> <span class="number">3.0</span> <span class="special">);</span> |
| |
| <span class="comment">// Add two vectors lazily and get the 2nd element.</span> |
| <span class="keyword">double</span> <span class="identifier">d1</span> <span class="special">=</span> <span class="special">(</span> <span class="identifier">v2</span> <span class="special">+</span> <span class="identifier">v3</span> <span class="special">)[</span> <span class="number">2</span> <span class="special">];</span> <span class="comment">// Look ma, no temporaries!</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">d1</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="comment">// Subtract two vectors and add the result to a third vector.</span> |
| <span class="identifier">v1</span> <span class="special">+=</span> <span class="identifier">v2</span> <span class="special">-</span> <span class="identifier">v3</span><span class="special">;</span> <span class="comment">// Still no temporaries!</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="char">'{'</span> <span class="special"><<</span> <span class="identifier">v1</span><span class="special">[</span><span class="number">0</span><span class="special">]</span> <span class="special"><<</span> <span class="char">','</span> <span class="special"><<</span> <span class="identifier">v1</span><span class="special">[</span><span class="number">1</span><span class="special">]</span> |
| <span class="special"><<</span> <span class="char">','</span> <span class="special"><<</span> <span class="identifier">v1</span><span class="special">[</span><span class="number">2</span><span class="special">]</span> <span class="special"><<</span> <span class="char">','</span> <span class="special"><<</span> <span class="identifier">v1</span><span class="special">[</span><span class="number">3</span><span class="special">]</span> <span class="special"><<</span> <span class="char">'}'</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="comment">// This expression is disallowed because it does not conform</span> |
| <span class="comment">// to the LazyVectorGrammar</span> |
| <span class="comment">//(v2 + v3) += v1;</span> |
| |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.examples.rgb"></a><a class="link" href="users_guide.html#boost_proto.users_guide.examples.rgb" title="RGB: Type Manipulations with Proto Transforms">RGB: Type Manipulations |
| with Proto Transforms</a> |
| </h4></div></div></div> |
| <p> |
| This is a simple example of doing arbitrary type manipulations with Proto |
| transforms. It takes some expression involving primary colors and combines |
| the colors according to arbitrary rules. It is a port of the RGB example |
| from <a href="http://www.codesourcery.com/pooma/download.html" target="_top">PETE</a>. |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="comment">///////////////////////////////////////////////////////////////////////////////</span> |
| <span class="comment">// Copyright 2008 Eric Niebler. Distributed under the Boost</span> |
| <span class="comment">// Software License, Version 1.0. (See accompanying file</span> |
| <span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span> |
| <span class="comment">//</span> |
| <span class="comment">// This is a simple example of doing arbitrary type manipulations with proto</span> |
| <span class="comment">// transforms. It takes some expression involving primary colors and combines</span> |
| <span class="comment">// the colors according to arbitrary rules. It is a port of the RGB example</span> |
| <span class="comment">// from PETE (http://www.codesourcery.com/pooma/download.html).</span> |
| |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">transform</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="keyword">namespace</span> <span class="identifier">proto</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">;</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">RedTag</span> |
| <span class="special">{</span> |
| <span class="keyword">friend</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="keyword">operator</span> <span class="special"><<(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="identifier">sout</span><span class="special">,</span> <span class="identifier">RedTag</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">sout</span> <span class="special"><<</span> <span class="string">"This expression is red."</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">BlueTag</span> |
| <span class="special">{</span> |
| <span class="keyword">friend</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="keyword">operator</span> <span class="special"><<(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="identifier">sout</span><span class="special">,</span> <span class="identifier">BlueTag</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">sout</span> <span class="special"><<</span> <span class="string">"This expression is blue."</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">GreenTag</span> |
| <span class="special">{</span> |
| <span class="keyword">friend</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="keyword">operator</span> <span class="special"><<(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="identifier">sout</span><span class="special">,</span> <span class="identifier">GreenTag</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">sout</span> <span class="special"><<</span> <span class="string">"This expression is green."</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">typedef</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">RedTag</span><span class="special">>::</span><span class="identifier">type</span> <span class="identifier">RedT</span><span class="special">;</span> |
| <span class="keyword">typedef</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">BlueTag</span><span class="special">>::</span><span class="identifier">type</span> <span class="identifier">BlueT</span><span class="special">;</span> |
| <span class="keyword">typedef</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">GreenTag</span><span class="special">>::</span><span class="identifier">type</span> <span class="identifier">GreenT</span><span class="special">;</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">Red</span><span class="special">;</span> |
| <span class="keyword">struct</span> <span class="identifier">Blue</span><span class="special">;</span> |
| <span class="keyword">struct</span> <span class="identifier">Green</span><span class="special">;</span> |
| |
| <span class="comment">///////////////////////////////////////////////////////////////////////////////</span> |
| <span class="comment">// A transform that produces new colors according to some arbitrary rules:</span> |
| <span class="comment">// red & green give blue, red & blue give green, blue and green give red.</span> |
| <span class="keyword">struct</span> <span class="identifier">Red</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><span class="identifier">Green</span><span class="special">,</span> <span class="identifier">Blue</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><span class="identifier">Blue</span><span class="special">,</span> <span class="identifier">Green</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><span class="identifier">Red</span><span class="special">,</span> <span class="identifier">Red</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">RedTag</span><span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">Green</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><span class="identifier">Red</span><span class="special">,</span> <span class="identifier">Blue</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><span class="identifier">Blue</span><span class="special">,</span> <span class="identifier">Red</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><span class="identifier">Green</span><span class="special">,</span> <span class="identifier">Green</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">GreenTag</span><span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">Blue</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><span class="identifier">Red</span><span class="special">,</span> <span class="identifier">Green</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><span class="identifier">Green</span><span class="special">,</span> <span class="identifier">Red</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><span class="identifier">Blue</span><span class="special">,</span> <span class="identifier">Blue</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">BlueTag</span><span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">RGB</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> <span class="identifier">Red</span><span class="special">,</span> <span class="identifier">RedTag</span><span class="special">()</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> <span class="identifier">Blue</span><span class="special">,</span> <span class="identifier">BlueTag</span><span class="special">()</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> <span class="identifier">Green</span><span class="special">,</span> <span class="identifier">GreenTag</span><span class="special">()</span> <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">void</span> <span class="identifier">printColor</span><span class="special">(</span><span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">int</span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="comment">// dummy state and data parameter, not used</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">RGB</span><span class="special">()(</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">i</span><span class="special">,</span> <span class="identifier">i</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="identifier">printColor</span><span class="special">(</span><span class="identifier">RedT</span><span class="special">()</span> <span class="special">+</span> <span class="identifier">GreenT</span><span class="special">());</span> |
| <span class="identifier">printColor</span><span class="special">(</span><span class="identifier">RedT</span><span class="special">()</span> <span class="special">+</span> <span class="identifier">GreenT</span><span class="special">()</span> <span class="special">+</span> <span class="identifier">BlueT</span><span class="special">());</span> |
| <span class="identifier">printColor</span><span class="special">(</span><span class="identifier">RedT</span><span class="special">()</span> <span class="special">+</span> <span class="special">(</span><span class="identifier">GreenT</span><span class="special">()</span> <span class="special">+</span> <span class="identifier">BlueT</span><span class="special">()));</span> |
| |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.examples.tarray"></a><a class="link" href="users_guide.html#boost_proto.users_guide.examples.tarray" title="TArray: A Simple Linear Algebra Library">TArray: A |
| Simple Linear Algebra Library</a> |
| </h4></div></div></div> |
| <p> |
| This example constructs a mini-library for linear algebra, using expression |
| templates to eliminate the need for temporaries when adding arrays of numbers. |
| It duplicates the TArray example from <a href="http://www.codesourcery.com/pooma/download.html" target="_top">PETE</a>. |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="comment">///////////////////////////////////////////////////////////////////////////////</span> |
| <span class="comment">// Copyright 2008 Eric Niebler. Distributed under the Boost</span> |
| <span class="comment">// Software License, Version 1.0. (See accompanying file</span> |
| <span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span> |
| <span class="comment">//</span> |
| <span class="comment">// This example constructs a mini-library for linear algebra, using</span> |
| <span class="comment">// expression templates to eliminate the need for temporaries when</span> |
| <span class="comment">// adding arrays of numbers. It duplicates the TArray example from</span> |
| <span class="comment">// PETE (http://www.codesourcery.com/pooma/download.html)</span> |
| |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mpl</span><span class="special">/</span><span class="keyword">int</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">context</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="keyword">namespace</span> <span class="identifier">mpl</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">mpl</span><span class="special">;</span> |
| <span class="keyword">namespace</span> <span class="identifier">proto</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">;</span> |
| <span class="keyword">using</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span><span class="special">;</span> |
| |
| <span class="comment">// This grammar describes which TArray expressions</span> |
| <span class="comment">// are allowed; namely, int and array terminals</span> |
| <span class="comment">// plus, minus, multiplies and divides of TArray expressions.</span> |
| <span class="keyword">struct</span> <span class="identifier">TArrayGrammar</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="keyword">int</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="keyword">int</span><span class="special">[</span><span class="number">3</span><span class="special">]</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span> <span class="identifier">TArrayGrammar</span><span class="special">,</span> <span class="identifier">TArrayGrammar</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">minus</span><span class="special"><</span> <span class="identifier">TArrayGrammar</span><span class="special">,</span> <span class="identifier">TArrayGrammar</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">multiplies</span><span class="special"><</span> <span class="identifier">TArrayGrammar</span><span class="special">,</span> <span class="identifier">TArrayGrammar</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">divides</span><span class="special"><</span> <span class="identifier">TArrayGrammar</span><span class="special">,</span> <span class="identifier">TArrayGrammar</span> <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">TArrayExpr</span><span class="special">;</span> |
| |
| <span class="comment">// Tell proto that in the TArrayDomain, all</span> |
| <span class="comment">// expressions should be wrapped in TArrayExpr<> and</span> |
| <span class="comment">// must conform to the TArrayGrammar</span> |
| <span class="keyword">struct</span> <span class="identifier">TArrayDomain</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">generator</span><span class="special"><</span><span class="identifier">TArrayExpr</span><span class="special">>,</span> <span class="identifier">TArrayGrammar</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Here is an evaluation context that indexes into a TArray</span> |
| <span class="comment">// expression, and combines the result.</span> |
| <span class="keyword">struct</span> <span class="identifier">TArraySubscriptCtx</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable_context</span><span class="special"><</span> <span class="identifier">TArraySubscriptCtx</span> <span class="keyword">const</span> <span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">int</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">TArraySubscriptCtx</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ptrdiff_t</span> <span class="identifier">i</span><span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">i_</span><span class="special">(</span><span class="identifier">i</span><span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="comment">// Index array terminals with our subscript. Everything</span> |
| <span class="comment">// else will be handled by the default evaluation context.</span> |
| <span class="keyword">int</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">,</span> <span class="keyword">int</span> <span class="keyword">const</span> <span class="special">(&</span><span class="identifier">data</span><span class="special">)[</span><span class="number">3</span><span class="special">])</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">data</span><span class="special">[</span><span class="keyword">this</span><span class="special">-></span><span class="identifier">i_</span><span class="special">];</span> |
| <span class="special">}</span> |
| |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">ptrdiff_t</span> <span class="identifier">i_</span><span class="special">;</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Here is an evaluation context that prints a TArray expression.</span> |
| <span class="keyword">struct</span> <span class="identifier">TArrayPrintCtx</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable_context</span><span class="special"><</span> <span class="identifier">TArrayPrintCtx</span> <span class="keyword">const</span> <span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">TArrayPrintCtx</span><span class="special">()</span> <span class="special">{}</span> |
| |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">i</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">i</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">,</span> <span class="keyword">int</span> <span class="keyword">const</span> <span class="special">(&</span><span class="identifier">arr</span><span class="special">)[</span><span class="number">3</span><span class="special">])</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="char">'{'</span> <span class="special"><<</span> <span class="identifier">arr</span><span class="special">[</span><span class="number">0</span><span class="special">]</span> <span class="special"><<</span> <span class="string">", "</span> <span class="special"><<</span> <span class="identifier">arr</span><span class="special">[</span><span class="number">1</span><span class="special">]</span> <span class="special"><<</span> <span class="string">", "</span> <span class="special"><<</span> <span class="identifier">arr</span><span class="special">[</span><span class="number">2</span><span class="special">]</span> <span class="special"><<</span> <span class="char">'}'</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">L</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">R</span><span class="special">></span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">plus</span><span class="special">,</span> <span class="identifier">L</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">l</span><span class="special">,</span> <span class="identifier">R</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">r</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="char">'('</span> <span class="special"><<</span> <span class="identifier">l</span> <span class="special"><<</span> <span class="string">" + "</span> <span class="special"><<</span> <span class="identifier">r</span> <span class="special"><<</span> <span class="char">')'</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">L</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">R</span><span class="special">></span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">minus</span><span class="special">,</span> <span class="identifier">L</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">l</span><span class="special">,</span> <span class="identifier">R</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">r</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="char">'('</span> <span class="special"><<</span> <span class="identifier">l</span> <span class="special"><<</span> <span class="string">" - "</span> <span class="special"><<</span> <span class="identifier">r</span> <span class="special"><<</span> <span class="char">')'</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">L</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">R</span><span class="special">></span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">multiplies</span><span class="special">,</span> <span class="identifier">L</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">l</span><span class="special">,</span> <span class="identifier">R</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">r</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">l</span> <span class="special"><<</span> <span class="string">" * "</span> <span class="special"><<</span> <span class="identifier">r</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">L</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">R</span><span class="special">></span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">divides</span><span class="special">,</span> <span class="identifier">L</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">l</span><span class="special">,</span> <span class="identifier">R</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">r</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">l</span> <span class="special"><<</span> <span class="string">" / "</span> <span class="special"><<</span> <span class="identifier">r</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Here is the domain-specific expression wrapper, which overrides</span> |
| <span class="comment">// operator [] to evaluate the expression using the TArraySubscriptCtx.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">TArrayExpr</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">TArrayExpr</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>,</span> <span class="identifier">TArrayDomain</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">TArrayExpr</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>,</span> <span class="identifier">TArrayDomain</span><span class="special">></span> <span class="identifier">base_type</span><span class="special">;</span> |
| |
| <span class="identifier">TArrayExpr</span><span class="special">(</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">expr</span> <span class="special">=</span> <span class="identifier">Expr</span><span class="special">()</span> <span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">base_type</span><span class="special">(</span> <span class="identifier">expr</span> <span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="comment">// Use the TArraySubscriptCtx to implement subscripting</span> |
| <span class="comment">// of a TArray expression tree.</span> |
| <span class="keyword">int</span> <span class="keyword">operator</span> <span class="special">[](</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ptrdiff_t</span> <span class="identifier">i</span> <span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">TArraySubscriptCtx</span> <span class="keyword">const</span> <span class="identifier">ctx</span><span class="special">(</span><span class="identifier">i</span><span class="special">);</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="comment">// Use the TArrayPrintCtx to display a TArray expression tree.</span> |
| <span class="keyword">friend</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="keyword">operator</span> <span class="special"><<(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span> <span class="special">&</span><span class="identifier">sout</span><span class="special">,</span> <span class="identifier">TArrayExpr</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">></span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">TArrayPrintCtx</span> <span class="keyword">const</span> <span class="identifier">ctx</span><span class="special">;</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Here is our TArray terminal, implemented in terms of TArrayExpr</span> |
| <span class="comment">// It is basically just an array of 3 integers.</span> |
| <span class="keyword">struct</span> <span class="identifier">TArray</span> |
| <span class="special">:</span> <span class="identifier">TArrayExpr</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="keyword">int</span><span class="special">[</span><span class="number">3</span><span class="special">]</span> <span class="special">>::</span><span class="identifier">type</span> <span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">explicit</span> <span class="identifier">TArray</span><span class="special">(</span> <span class="keyword">int</span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">j</span> <span class="special">=</span> <span class="number">0</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">k</span> <span class="special">=</span> <span class="number">0</span> <span class="special">)</span> |
| <span class="special">{</span> |
| <span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="number">0</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">i</span><span class="special">;</span> |
| <span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="number">1</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">j</span><span class="special">;</span> |
| <span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="number">2</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">k</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="comment">// Here we override operator [] to give read/write access to</span> |
| <span class="comment">// the elements of the array. (We could use the TArrayExpr</span> |
| <span class="comment">// operator [] if we made the subscript context smarter about</span> |
| <span class="comment">// returning non-const reference when appropriate.)</span> |
| <span class="keyword">int</span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">[](</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ptrdiff_t</span> <span class="identifier">i</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">value</span><span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="identifier">i</span><span class="special">];</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">int</span> <span class="keyword">const</span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">[](</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ptrdiff_t</span> <span class="identifier">i</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">value</span><span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="identifier">i</span><span class="special">];</span> |
| <span class="special">}</span> |
| |
| <span class="comment">// Here we define a operator = for TArray terminals that</span> |
| <span class="comment">// takes a TArray expression.</span> |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Expr</span> <span class="special">></span> |
| <span class="identifier">TArray</span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">=(</span><span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="comment">// proto::as_expr<TArrayDomain>(expr) is the same as</span> |
| <span class="comment">// expr unless expr is an integer, in which case it</span> |
| <span class="comment">// is made into a TArrayExpr terminal first.</span> |
| <span class="keyword">return</span> <span class="keyword">this</span><span class="special">-></span><span class="identifier">assign</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special"><</span><span class="identifier">TArrayDomain</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">));</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Expr</span> <span class="special">></span> |
| <span class="identifier">TArray</span> <span class="special">&</span><span class="identifier">printAssign</span><span class="special">(</span><span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="special">*</span><span class="keyword">this</span> <span class="special">=</span> <span class="identifier">expr</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="special">*</span><span class="keyword">this</span> <span class="special"><<</span> <span class="string">" = "</span> <span class="special"><<</span> <span class="identifier">expr</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| <span class="keyword">return</span> <span class="special">*</span><span class="keyword">this</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">private</span><span class="special">:</span> |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Expr</span> <span class="special">></span> |
| <span class="identifier">TArray</span> <span class="special">&</span><span class="identifier">assign</span><span class="special">(</span><span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="comment">// expr[i] here uses TArraySubscriptCtx under the covers.</span> |
| <span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="number">0</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">expr</span><span class="special">[</span><span class="number">0</span><span class="special">];</span> |
| <span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="number">1</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">expr</span><span class="special">[</span><span class="number">1</span><span class="special">];</span> |
| <span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="number">2</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">expr</span><span class="special">[</span><span class="number">2</span><span class="special">];</span> |
| <span class="keyword">return</span> <span class="special">*</span><span class="keyword">this</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="identifier">TArray</span> <span class="identifier">a</span><span class="special">(</span><span class="number">3</span><span class="special">,</span><span class="number">1</span><span class="special">,</span><span class="number">2</span><span class="special">);</span> |
| |
| <span class="identifier">TArray</span> <span class="identifier">b</span><span class="special">;</span> |
| |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">a</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">b</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="identifier">b</span><span class="special">[</span><span class="number">0</span><span class="special">]</span> <span class="special">=</span> <span class="number">7</span><span class="special">;</span> <span class="identifier">b</span><span class="special">[</span><span class="number">1</span><span class="special">]</span> <span class="special">=</span> <span class="number">33</span><span class="special">;</span> <span class="identifier">b</span><span class="special">[</span><span class="number">2</span><span class="special">]</span> <span class="special">=</span> <span class="special">-</span><span class="number">99</span><span class="special">;</span> |
| |
| <span class="identifier">TArray</span> <span class="identifier">c</span><span class="special">(</span><span class="identifier">a</span><span class="special">);</span> |
| |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">c</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="identifier">a</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> |
| |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">a</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">b</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">c</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="identifier">a</span> <span class="special">=</span> <span class="identifier">b</span> <span class="special">+</span> <span class="identifier">c</span><span class="special">;</span> |
| |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">a</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="identifier">a</span><span class="special">.</span><span class="identifier">printAssign</span><span class="special">(</span><span class="identifier">b</span><span class="special">+</span><span class="identifier">c</span><span class="special">*(</span><span class="identifier">b</span> <span class="special">+</span> <span class="number">3</span><span class="special">*</span><span class="identifier">c</span><span class="special">));</span> |
| |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.examples.vec3"></a><a class="link" href="users_guide.html#boost_proto.users_guide.examples.vec3" title="Vec3: Computing With Transforms and Contexts">Vec3: Computing |
| With Transforms and Contexts</a> |
| </h4></div></div></div> |
| <p> |
| This is a simple example using <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><></span></code> to extend a terminal type with |
| additional behaviors, and using custom contexts and <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">()</span></code> for evaluating expressions. It is a port |
| of the Vec3 example from <a href="http://www.codesourcery.com/pooma/download.html" target="_top">PETE</a>. |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="comment">///////////////////////////////////////////////////////////////////////////////</span> |
| <span class="comment">// Copyright 2008 Eric Niebler. Distributed under the Boost</span> |
| <span class="comment">// Software License, Version 1.0. (See accompanying file</span> |
| <span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span> |
| <span class="comment">//</span> |
| <span class="comment">// This is a simple example using proto::extends to extend a terminal type with</span> |
| <span class="comment">// additional behaviors, and using custom contexts and proto::eval for</span> |
| <span class="comment">// evaluating expressions. It is a port of the Vec3 example</span> |
| <span class="comment">// from PETE (http://www.codesourcery.com/pooma/download.html).</span> |
| |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">functional</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">assert</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mpl</span><span class="special">/</span><span class="keyword">int</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">context</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">proto_typeof</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">transform</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="keyword">namespace</span> <span class="identifier">mpl</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">mpl</span><span class="special">;</span> |
| <span class="keyword">namespace</span> <span class="identifier">proto</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">;</span> |
| <span class="keyword">using</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span><span class="special">;</span> |
| |
| <span class="comment">// Here is an evaluation context that indexes into a Vec3</span> |
| <span class="comment">// expression, and combines the result.</span> |
| <span class="keyword">struct</span> <span class="identifier">Vec3SubscriptCtx</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable_context</span><span class="special"><</span> <span class="identifier">Vec3SubscriptCtx</span> <span class="keyword">const</span> <span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">int</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">Vec3SubscriptCtx</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">i</span><span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">i_</span><span class="special">(</span><span class="identifier">i</span><span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="comment">// Index array terminals with our subscript. Everything</span> |
| <span class="comment">// else will be handled by the default evaluation context.</span> |
| <span class="keyword">int</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">,</span> <span class="keyword">int</span> <span class="keyword">const</span> <span class="special">(&</span><span class="identifier">arr</span><span class="special">)[</span><span class="number">3</span><span class="special">])</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">arr</span><span class="special">[</span><span class="keyword">this</span><span class="special">-></span><span class="identifier">i_</span><span class="special">];</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">int</span> <span class="identifier">i_</span><span class="special">;</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Here is an evaluation context that counts the number</span> |
| <span class="comment">// of Vec3 terminals in an expression.</span> |
| <span class="keyword">struct</span> <span class="identifier">CountLeavesCtx</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable_context</span><span class="special"><</span> <span class="identifier">CountLeavesCtx</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">null_context</span> <span class="special">></span> |
| <span class="special">{</span> |
| <span class="identifier">CountLeavesCtx</span><span class="special">()</span> |
| <span class="special">:</span> <span class="identifier">count</span><span class="special">(</span><span class="number">0</span><span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="keyword">typedef</span> <span class="keyword">void</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="keyword">void</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">,</span> <span class="keyword">int</span> <span class="keyword">const</span><span class="special">(&)[</span><span class="number">3</span><span class="special">])</span> |
| <span class="special">{</span> |
| <span class="special">++</span><span class="keyword">this</span><span class="special">-></span><span class="identifier">count</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">int</span> <span class="identifier">count</span><span class="special">;</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">iplus</span> <span class="special">:</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><</span><span class="keyword">int</span><span class="special">>,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable</span> <span class="special">{};</span> |
| |
| <span class="comment">// Here is a transform that does the same thing as the above context.</span> |
| <span class="comment">// It demonstrates the use of the std::plus<> function object</span> |
| <span class="comment">// with the fold transform. With minor modifications, this</span> |
| <span class="comment">// transform could be used to calculate the leaf count at compile</span> |
| <span class="comment">// time, rather than at runtime.</span> |
| <span class="keyword">struct</span> <span class="identifier">CountLeaves</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="comment">// match a Vec3 terminal, return 1</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">[</span><span class="number">3</span><span class="special">]>,</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">int_</span><span class="special"><</span><span class="number">1</span><span class="special">>()</span> <span class="special">></span> |
| <span class="comment">// match a terminal, return int() (which is 0)</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">_</span><span class="special">>,</span> <span class="keyword">int</span><span class="special">()</span> <span class="special">></span> |
| <span class="comment">// fold everything else, using std::plus<> to add</span> |
| <span class="comment">// the leaf count of each child to the accumulated state.</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">otherwise</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">fold</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> <span class="keyword">int</span><span class="special">(),</span> <span class="identifier">iplus</span><span class="special">(</span><span class="identifier">CountLeaves</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span><span class="special">)</span> <span class="special">></span> <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Here is the Vec3 struct, which is a vector of 3 integers.</span> |
| <span class="keyword">struct</span> <span class="identifier">Vec3</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="keyword">int</span><span class="special">[</span><span class="number">3</span><span class="special">]>::</span><span class="identifier">type</span><span class="special">,</span> <span class="identifier">Vec3</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">explicit</span> <span class="identifier">Vec3</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">i</span><span class="special">=</span><span class="number">0</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">j</span><span class="special">=</span><span class="number">0</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">k</span><span class="special">=</span><span class="number">0</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="number">0</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">i</span><span class="special">;</span> |
| <span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="number">1</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">j</span><span class="special">;</span> |
| <span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="number">2</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">k</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">int</span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">[](</span><span class="keyword">int</span> <span class="identifier">i</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">value</span><span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="identifier">i</span><span class="special">];</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">int</span> <span class="keyword">const</span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">[](</span><span class="keyword">int</span> <span class="identifier">i</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">value</span><span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="identifier">i</span><span class="special">];</span> |
| <span class="special">}</span> |
| |
| <span class="comment">// Here we define a operator = for Vec3 terminals that</span> |
| <span class="comment">// takes a Vec3 expression.</span> |
| <span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">Expr</span> <span class="special">></span> |
| <span class="identifier">Vec3</span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">=(</span><span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span> <span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="identifier">Vec3SubscriptCtx</span> <span class="keyword">const</span> <span class="identifier">CVec3SubscriptCtx</span><span class="special">;</span> |
| <span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="number">0</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special">(</span><span class="identifier">expr</span><span class="special">),</span> <span class="identifier">CVec3SubscriptCtx</span><span class="special">(</span><span class="number">0</span><span class="special">));</span> |
| <span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="number">1</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special">(</span><span class="identifier">expr</span><span class="special">),</span> <span class="identifier">CVec3SubscriptCtx</span><span class="special">(</span><span class="number">1</span><span class="special">));</span> |
| <span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="number">2</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special">(</span><span class="identifier">expr</span><span class="special">),</span> <span class="identifier">CVec3SubscriptCtx</span><span class="special">(</span><span class="number">2</span><span class="special">));</span> |
| <span class="keyword">return</span> <span class="special">*</span><span class="keyword">this</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">void</span> <span class="identifier">print</span><span class="special">()</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="char">'{'</span> <span class="special"><<</span> <span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="number">0</span><span class="special">]</span> |
| <span class="special"><<</span> <span class="string">", "</span> <span class="special"><<</span> <span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="number">1</span><span class="special">]</span> |
| <span class="special"><<</span> <span class="string">", "</span> <span class="special"><<</span> <span class="special">(*</span><span class="keyword">this</span><span class="special">)[</span><span class="number">2</span><span class="special">]</span> |
| <span class="special"><<</span> <span class="char">'}'</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// The count_leaves() function uses the CountLeaves transform and</span> |
| <span class="comment">// to count the number of leaves in an expression.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">int</span> <span class="identifier">count_leaves</span><span class="special">(</span><span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="comment">// Count the number of Vec3 terminals using the</span> |
| <span class="comment">// CountLeavesCtx evaluation context.</span> |
| <span class="identifier">CountLeavesCtx</span> <span class="identifier">ctx</span><span class="special">;</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| |
| <span class="comment">// This is another way to count the leaves using a transform.</span> |
| <span class="keyword">int</span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> |
| <span class="identifier">BOOST_ASSERT</span><span class="special">(</span> <span class="identifier">CountLeaves</span><span class="special">()(</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">i</span><span class="special">,</span> <span class="identifier">i</span><span class="special">)</span> <span class="special">==</span> <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">count</span> <span class="special">);</span> |
| |
| <span class="keyword">return</span> <span class="identifier">ctx</span><span class="special">.</span><span class="identifier">count</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="identifier">Vec3</span> <span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">,</span> <span class="identifier">c</span><span class="special">;</span> |
| |
| <span class="identifier">c</span> <span class="special">=</span> <span class="number">4</span><span class="special">;</span> |
| |
| <span class="identifier">b</span><span class="special">[</span><span class="number">0</span><span class="special">]</span> <span class="special">=</span> <span class="special">-</span><span class="number">1</span><span class="special">;</span> |
| <span class="identifier">b</span><span class="special">[</span><span class="number">1</span><span class="special">]</span> <span class="special">=</span> <span class="special">-</span><span class="number">2</span><span class="special">;</span> |
| <span class="identifier">b</span><span class="special">[</span><span class="number">2</span><span class="special">]</span> <span class="special">=</span> <span class="special">-</span><span class="number">3</span><span class="special">;</span> |
| |
| <span class="identifier">a</span> <span class="special">=</span> <span class="identifier">b</span> <span class="special">+</span> <span class="identifier">c</span><span class="special">;</span> |
| |
| <span class="identifier">a</span><span class="special">.</span><span class="identifier">print</span><span class="special">();</span> |
| |
| <span class="identifier">Vec3</span> <span class="identifier">d</span><span class="special">;</span> |
| <span class="identifier">BOOST_PROTO_AUTO</span><span class="special">(</span><span class="identifier">expr1</span><span class="special">,</span> <span class="identifier">b</span> <span class="special">+</span> <span class="identifier">c</span><span class="special">);</span> |
| <span class="identifier">d</span> <span class="special">=</span> <span class="identifier">expr1</span><span class="special">;</span> |
| <span class="identifier">d</span><span class="special">.</span><span class="identifier">print</span><span class="special">();</span> |
| |
| <span class="keyword">int</span> <span class="identifier">num</span> <span class="special">=</span> <span class="identifier">count_leaves</span><span class="special">(</span><span class="identifier">expr1</span><span class="special">);</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">num</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="identifier">BOOST_PROTO_AUTO</span><span class="special">(</span><span class="identifier">expr2</span><span class="special">,</span> <span class="identifier">b</span> <span class="special">+</span> <span class="number">3</span> <span class="special">*</span> <span class="identifier">c</span><span class="special">);</span> |
| <span class="identifier">num</span> <span class="special">=</span> <span class="identifier">count_leaves</span><span class="special">(</span><span class="identifier">expr2</span><span class="special">);</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">num</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="identifier">BOOST_PROTO_AUTO</span><span class="special">(</span><span class="identifier">expr3</span><span class="special">,</span> <span class="identifier">b</span> <span class="special">+</span> <span class="identifier">c</span> <span class="special">*</span> <span class="identifier">d</span><span class="special">);</span> |
| <span class="identifier">num</span> <span class="special">=</span> <span class="identifier">count_leaves</span><span class="special">(</span><span class="identifier">expr3</span><span class="special">);</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">num</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.examples.vector"></a><a class="link" href="users_guide.html#boost_proto.users_guide.examples.vector" title="Vector: Adapting a Non-Proto Terminal Type">Vector: Adapting |
| a Non-Proto Terminal Type</a> |
| </h4></div></div></div> |
| <p> |
| This is an example of using <code class="computeroutput"><span class="identifier">BOOST_PROTO_DEFINE_OPERATORS</span><span class="special">()</span></code> to Protofy expressions using <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><></span></code>, |
| a non-Proto type. It is a port of the Vector example from <a href="http://www.codesourcery.com/pooma/download.html" target="_top">PETE</a>. |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="comment">///////////////////////////////////////////////////////////////////////////////</span> |
| <span class="comment">// Copyright 2008 Eric Niebler. Distributed under the Boost</span> |
| <span class="comment">// Software License, Version 1.0. (See accompanying file</span> |
| <span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span> |
| <span class="comment">//</span> |
| <span class="comment">// This is an example of using BOOST_PROTO_DEFINE_OPERATORS to Protofy</span> |
| <span class="comment">// expressions using std::vector<>, a non-proto type. It is a port of the</span> |
| <span class="comment">// Vector example from PETE (http://www.codesourcery.com/pooma/download.html).</span> |
| |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">vector</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">stdexcept</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mpl</span><span class="special">/</span><span class="keyword">bool</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">debug</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">context</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">utility</span><span class="special">/</span><span class="identifier">enable_if</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="keyword">namespace</span> <span class="identifier">mpl</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">mpl</span><span class="special">;</span> |
| <span class="keyword">namespace</span> <span class="identifier">proto</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">;</span> |
| <span class="keyword">using</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span><span class="special">;</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">VectorExpr</span><span class="special">;</span> |
| |
| <span class="comment">// Here is an evaluation context that indexes into a std::vector</span> |
| <span class="comment">// expression and combines the result.</span> |
| <span class="keyword">struct</span> <span class="identifier">VectorSubscriptCtx</span> |
| <span class="special">{</span> |
| <span class="identifier">VectorSubscriptCtx</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">i</span><span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">i_</span><span class="special">(</span><span class="identifier">i</span><span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="comment">// Unless this is a vector terminal, use the</span> |
| <span class="comment">// default evaluation context</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">EnableIf</span> <span class="special">=</span> <span class="keyword">void</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">default_eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">VectorSubscriptCtx</span> <span class="keyword">const</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Index vector terminals with our subscript.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span><span class="special"><</span> |
| <span class="identifier">Expr</span> |
| <span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">enable_if</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> <span class="identifier">_</span><span class="special">></span> <span class="special">></span> <span class="special">></span> |
| <span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">value</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="identifier">type</span><span class="special">::</span><span class="identifier">value_type</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">result_type</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">Expr</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">VectorSubscriptCtx</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">ctx</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">value</span><span class="special">(</span><span class="identifier">expr</span><span class="special">)[</span><span class="identifier">ctx</span><span class="special">.</span><span class="identifier">i_</span><span class="special">];</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">i_</span><span class="special">;</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Here is an evaluation context that verifies that all the</span> |
| <span class="comment">// vectors in an expression have the same size.</span> |
| <span class="keyword">struct</span> <span class="identifier">VectorSizeCtx</span> |
| <span class="special">{</span> |
| <span class="identifier">VectorSizeCtx</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">size</span><span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">size_</span><span class="special">(</span><span class="identifier">size</span><span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="comment">// Unless this is a vector terminal, use the</span> |
| <span class="comment">// null evaluation context</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">EnableIf</span> <span class="special">=</span> <span class="keyword">void</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">null_eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">VectorSizeCtx</span> <span class="keyword">const</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Index array terminals with our subscript. Everything</span> |
| <span class="comment">// else will be handled by the default evaluation context.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span><span class="special"><</span> |
| <span class="identifier">Expr</span> |
| <span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">enable_if</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> <span class="identifier">_</span><span class="special">></span> <span class="special">></span> <span class="special">></span> |
| <span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">void</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">result_type</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">Expr</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">VectorSizeCtx</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">ctx</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">if</span><span class="special">(</span><span class="identifier">ctx</span><span class="special">.</span><span class="identifier">size_</span> <span class="special">!=</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">value</span><span class="special">(</span><span class="identifier">expr</span><span class="special">).</span><span class="identifier">size</span><span class="special">())</span> |
| <span class="special">{</span> |
| <span class="keyword">throw</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">runtime_error</span><span class="special">(</span><span class="string">"LHS and RHS are not compatible"</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">size_</span><span class="special">;</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// A grammar which matches all the assignment operators,</span> |
| <span class="comment">// so we can easily disable them.</span> |
| <span class="keyword">struct</span> <span class="identifier">AssignOps</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">switch_</span><span class="special"><</span><span class="keyword">struct</span> <span class="identifier">AssignOpsCases</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Here are the cases used by the switch_ above.</span> |
| <span class="keyword">struct</span> <span class="identifier">AssignOpsCases</span> |
| <span class="special">{</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Tag</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">D</span> <span class="special">=</span> <span class="number">0</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span> <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">not_</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">plus_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">minus_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">multiplies_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">divides_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">modulus_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">shift_left_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">shift_right_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">bitwise_and_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">bitwise_or_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">bitwise_xor_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// A vector grammar is a terminal or some op that is not an</span> |
| <span class="comment">// assignment op. (Assignment will be handled specially.)</span> |
| <span class="keyword">struct</span> <span class="identifier">VectorGrammar</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">and_</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">nary_expr</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">vararg</span><span class="special"><</span><span class="identifier">VectorGrammar</span><span class="special">></span> <span class="special">>,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">not_</span><span class="special"><</span><span class="identifier">AssignOps</span><span class="special">></span> <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Expressions in the vector domain will be wrapped in VectorExpr<></span> |
| <span class="comment">// and must conform to the VectorGrammar</span> |
| <span class="keyword">struct</span> <span class="identifier">VectorDomain</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">generator</span><span class="special"><</span><span class="identifier">VectorExpr</span><span class="special">>,</span> <span class="identifier">VectorGrammar</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Here is VectorExpr, which extends a proto expr type by</span> |
| <span class="comment">// giving it an operator [] which uses the VectorSubscriptCtx</span> |
| <span class="comment">// to evaluate an expression with a given index.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">VectorExpr</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">VectorExpr</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>,</span> <span class="identifier">VectorDomain</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">explicit</span> <span class="identifier">VectorExpr</span><span class="special">(</span><span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">VectorExpr</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>,</span> <span class="identifier">VectorDomain</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="comment">// Use the VectorSubscriptCtx to implement subscripting</span> |
| <span class="comment">// of a Vector expression tree.</span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">eval</span><span class="special"><</span><span class="identifier">Expr</span> <span class="keyword">const</span><span class="special">,</span> <span class="identifier">VectorSubscriptCtx</span> <span class="keyword">const</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="keyword">operator</span> <span class="special">[](</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">i</span> <span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">VectorSubscriptCtx</span> <span class="keyword">const</span> <span class="identifier">ctx</span><span class="special">(</span><span class="identifier">i</span><span class="special">);</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Define a trait type for detecting vector terminals, to</span> |
| <span class="comment">// be used by the BOOST_PROTO_DEFINE_OPERATORS macro below.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">IsVector</span> |
| <span class="special">:</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">false_</span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">IsVector</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">></span> |
| <span class="special">:</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">true_</span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">namespace</span> <span class="identifier">VectorOps</span> |
| <span class="special">{</span> |
| <span class="comment">// This defines all the overloads to make expressions involving</span> |
| <span class="comment">// std::vector to build expression templates.</span> |
| <span class="identifier">BOOST_PROTO_DEFINE_OPERATORS</span><span class="special">(</span><span class="identifier">IsVector</span><span class="special">,</span> <span class="identifier">VectorDomain</span><span class="special">)</span> |
| |
| <span class="keyword">typedef</span> <span class="identifier">VectorSubscriptCtx</span> <span class="keyword">const</span> <span class="identifier">CVectorSubscriptCtx</span><span class="special">;</span> |
| |
| <span class="comment">// Assign to a vector from some expression.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">&</span><span class="identifier">assign</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">&</span><span class="identifier">arr</span><span class="special">,</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">VectorSizeCtx</span> <span class="keyword">const</span> <span class="identifier">size</span><span class="special">(</span><span class="identifier">arr</span><span class="special">.</span><span class="identifier">size</span><span class="special">());</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special"><</span><span class="identifier">VectorDomain</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">),</span> <span class="identifier">size</span><span class="special">);</span> <span class="comment">// will throw if the sizes don't match</span> |
| <span class="keyword">for</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="identifier">i</span> <span class="special"><</span> <span class="identifier">arr</span><span class="special">.</span><span class="identifier">size</span><span class="special">();</span> <span class="special">++</span><span class="identifier">i</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">arr</span><span class="special">[</span><span class="identifier">i</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special"><</span><span class="identifier">VectorDomain</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">)[</span><span class="identifier">i</span><span class="special">];</span> |
| <span class="special">}</span> |
| <span class="keyword">return</span> <span class="identifier">arr</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="comment">// Add-assign to a vector from some expression.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">+=(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">&</span><span class="identifier">arr</span><span class="special">,</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">VectorSizeCtx</span> <span class="keyword">const</span> <span class="identifier">size</span><span class="special">(</span><span class="identifier">arr</span><span class="special">.</span><span class="identifier">size</span><span class="special">());</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special"><</span><span class="identifier">VectorDomain</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">),</span> <span class="identifier">size</span><span class="special">);</span> <span class="comment">// will throw if the sizes don't match</span> |
| <span class="keyword">for</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="identifier">i</span> <span class="special"><</span> <span class="identifier">arr</span><span class="special">.</span><span class="identifier">size</span><span class="special">();</span> <span class="special">++</span><span class="identifier">i</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">arr</span><span class="special">[</span><span class="identifier">i</span><span class="special">]</span> <span class="special">+=</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special"><</span><span class="identifier">VectorDomain</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">)[</span><span class="identifier">i</span><span class="special">];</span> |
| <span class="special">}</span> |
| <span class="keyword">return</span> <span class="identifier">arr</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">VectorOps</span><span class="special">;</span> |
| |
| <span class="keyword">int</span> <span class="identifier">i</span><span class="special">;</span> |
| <span class="keyword">const</span> <span class="keyword">int</span> <span class="identifier">n</span> <span class="special">=</span> <span class="number">10</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="identifier">a</span><span class="special">,</span><span class="identifier">b</span><span class="special">,</span><span class="identifier">c</span><span class="special">,</span><span class="identifier">d</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span> <span class="identifier">e</span><span class="special">(</span><span class="identifier">n</span><span class="special">);</span> |
| |
| <span class="keyword">for</span> <span class="special">(</span><span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="identifier">i</span> <span class="special"><</span> <span class="identifier">n</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">a</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">i</span><span class="special">);</span> |
| <span class="identifier">b</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">2</span><span class="special">*</span><span class="identifier">i</span><span class="special">);</span> |
| <span class="identifier">c</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">3</span><span class="special">*</span><span class="identifier">i</span><span class="special">);</span> |
| <span class="identifier">d</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">i</span><span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="identifier">VectorOps</span><span class="special">::</span><span class="identifier">assign</span><span class="special">(</span><span class="identifier">b</span><span class="special">,</span> <span class="number">2</span><span class="special">);</span> |
| <span class="identifier">VectorOps</span><span class="special">::</span><span class="identifier">assign</span><span class="special">(</span><span class="identifier">d</span><span class="special">,</span> <span class="identifier">a</span> <span class="special">+</span> <span class="identifier">b</span> <span class="special">*</span> <span class="identifier">c</span><span class="special">);</span> |
| <span class="identifier">a</span> <span class="special">+=</span> <span class="identifier">if_else</span><span class="special">(</span><span class="identifier">d</span> <span class="special"><</span> <span class="number">30</span><span class="special">,</span> <span class="identifier">b</span><span class="special">,</span> <span class="identifier">c</span><span class="special">);</span> |
| |
| <span class="identifier">VectorOps</span><span class="special">::</span><span class="identifier">assign</span><span class="special">(</span><span class="identifier">e</span><span class="special">,</span> <span class="identifier">c</span><span class="special">);</span> |
| <span class="identifier">e</span> <span class="special">+=</span> <span class="identifier">e</span> <span class="special">-</span> <span class="number">4</span> <span class="special">/</span> <span class="special">(</span><span class="identifier">c</span> <span class="special">+</span> <span class="number">1</span><span class="special">);</span> |
| |
| <span class="keyword">for</span> <span class="special">(</span><span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="identifier">i</span> <span class="special"><</span> <span class="identifier">n</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> |
| <span class="special"><<</span> <span class="string">" a("</span> <span class="special"><<</span> <span class="identifier">i</span> <span class="special"><<</span> <span class="string">") = "</span> <span class="special"><<</span> <span class="identifier">a</span><span class="special">[</span><span class="identifier">i</span><span class="special">]</span> |
| <span class="special"><<</span> <span class="string">" b("</span> <span class="special"><<</span> <span class="identifier">i</span> <span class="special"><<</span> <span class="string">") = "</span> <span class="special"><<</span> <span class="identifier">b</span><span class="special">[</span><span class="identifier">i</span><span class="special">]</span> |
| <span class="special"><<</span> <span class="string">" c("</span> <span class="special"><<</span> <span class="identifier">i</span> <span class="special"><<</span> <span class="string">") = "</span> <span class="special"><<</span> <span class="identifier">c</span><span class="special">[</span><span class="identifier">i</span><span class="special">]</span> |
| <span class="special"><<</span> <span class="string">" d("</span> <span class="special"><<</span> <span class="identifier">i</span> <span class="special"><<</span> <span class="string">") = "</span> <span class="special"><<</span> <span class="identifier">d</span><span class="special">[</span><span class="identifier">i</span><span class="special">]</span> |
| <span class="special"><<</span> <span class="string">" e("</span> <span class="special"><<</span> <span class="identifier">i</span> <span class="special"><<</span> <span class="string">") = "</span> <span class="special"><<</span> <span class="identifier">e</span><span class="special">[</span><span class="identifier">i</span><span class="special">]</span> |
| <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.examples.mixed"></a><a class="link" href="users_guide.html#boost_proto.users_guide.examples.mixed" title="Mixed: Adapting Several Non-Proto Terminal Types">Mixed: Adapting |
| Several Non-Proto Terminal Types</a> |
| </h4></div></div></div> |
| <p> |
| This is an example of using <code class="computeroutput"><span class="identifier">BOOST_PROTO_DEFINE_OPERATORS</span><span class="special">()</span></code> to Protofy expressions using <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><></span></code> |
| and <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><></span></code>, |
| non-Proto types. It is a port of the Mixed example from <a href="http://www.codesourcery.com/pooma/download.html" target="_top">PETE</a>. |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="comment">///////////////////////////////////////////////////////////////////////////////</span> |
| <span class="comment">// Copyright 2008 Eric Niebler. Distributed under the Boost</span> |
| <span class="comment">// Software License, Version 1.0. (See accompanying file</span> |
| <span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span> |
| <span class="comment">//</span> |
| <span class="comment">// This is an example of using BOOST_PROTO_DEFINE_OPERATORS to Protofy</span> |
| <span class="comment">// expressions using std::vector<> and std::list, non-proto types. It is a port</span> |
| <span class="comment">// of the Mixed example from PETE.</span> |
| <span class="comment">// (http://www.codesourcery.com/pooma/download.html).</span> |
| |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">list</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">cmath</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">vector</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">complex</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">stdexcept</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">debug</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">context</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">transform</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">utility</span><span class="special">/</span><span class="identifier">enable_if</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">typeof</span><span class="special">/</span><span class="identifier">std</span><span class="special">/</span><span class="identifier">list</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">typeof</span><span class="special">/</span><span class="identifier">std</span><span class="special">/</span><span class="identifier">vector</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">typeof</span><span class="special">/</span><span class="identifier">std</span><span class="special">/</span><span class="identifier">complex</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">type_traits</span><span class="special">/</span><span class="identifier">remove_reference</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="keyword">namespace</span> <span class="identifier">proto</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">;</span> |
| <span class="keyword">namespace</span> <span class="identifier">mpl</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">mpl</span><span class="special">;</span> |
| <span class="keyword">using</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span><span class="special">;</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">MixedExpr</span><span class="special">;</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Iter</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">iterator_wrapper</span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="identifier">Iter</span> <span class="identifier">iterator</span><span class="special">;</span> |
| |
| <span class="keyword">explicit</span> <span class="identifier">iterator_wrapper</span><span class="special">(</span><span class="identifier">Iter</span> <span class="identifier">iter</span><span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">it</span><span class="special">(</span><span class="identifier">iter</span><span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="keyword">mutable</span> <span class="identifier">Iter</span> <span class="identifier">it</span><span class="special">;</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">begin</span> <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable</span> |
| <span class="special">{</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">Sig</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">result</span><span class="special">;</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">This</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">Cont</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">result</span><span class="special"><</span><span class="identifier">This</span><span class="special">(</span><span class="identifier">Cont</span><span class="special">)></span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special"><</span> |
| <span class="identifier">iterator_wrapper</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">remove_reference</span><span class="special"><</span><span class="identifier">Cont</span><span class="special">>::</span><span class="identifier">type</span><span class="special">::</span><span class="identifier">const_iterator</span><span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Cont</span><span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">result</span><span class="special"><</span><span class="identifier">begin</span><span class="special">(</span><span class="identifier">Cont</span> <span class="keyword">const</span> <span class="special">&)>::</span><span class="identifier">type</span> |
| <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">Cont</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">cont</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">iterator_wrapper</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Cont</span><span class="special">::</span><span class="identifier">const_iterator</span><span class="special">></span> <span class="identifier">it</span><span class="special">(</span><span class="identifier">cont</span><span class="special">.</span><span class="identifier">begin</span><span class="special">());</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special">(</span><span class="identifier">it</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Here is a grammar that replaces vector and list terminals with their</span> |
| <span class="comment">// begin iterators</span> |
| <span class="keyword">struct</span> <span class="identifier">Begin</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> <span class="identifier">_</span><span class="special">></span> <span class="special">>,</span> <span class="identifier">begin</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">)</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> <span class="identifier">_</span><span class="special">></span> <span class="special">>,</span> <span class="identifier">begin</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">)</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">nary_expr</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">vararg</span><span class="special"><</span><span class="identifier">Begin</span><span class="special">></span> <span class="special">></span> <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Here is an evaluation context that dereferences iterator</span> |
| <span class="comment">// terminals.</span> |
| <span class="keyword">struct</span> <span class="identifier">DereferenceCtx</span> |
| <span class="special">{</span> |
| <span class="comment">// Unless this is an iterator terminal, use the</span> |
| <span class="comment">// default evaluation context</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">EnableIf</span> <span class="special">=</span> <span class="keyword">void</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">default_eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">DereferenceCtx</span> <span class="keyword">const</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Dereference iterator terminals.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span><span class="special"><</span> |
| <span class="identifier">Expr</span> |
| <span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">enable_if</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">iterator_wrapper</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> <span class="special">></span> <span class="special">></span> |
| <span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">value</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>::</span><span class="identifier">type</span> <span class="identifier">IteratorWrapper</span><span class="special">;</span> |
| <span class="keyword">typedef</span> <span class="keyword">typename</span> <span class="identifier">IteratorWrapper</span><span class="special">::</span><span class="identifier">iterator</span> <span class="identifier">iterator</span><span class="special">;</span> |
| <span class="keyword">typedef</span> <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">iterator_traits</span><span class="special"><</span><span class="identifier">iterator</span><span class="special">>::</span><span class="identifier">reference</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">result_type</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">Expr</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">DereferenceCtx</span> <span class="keyword">const</span> <span class="special">&)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="special">*</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">value</span><span class="special">(</span><span class="identifier">expr</span><span class="special">).</span><span class="identifier">it</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Here is an evaluation context that increments iterator</span> |
| <span class="comment">// terminals.</span> |
| <span class="keyword">struct</span> <span class="identifier">IncrementCtx</span> |
| <span class="special">{</span> |
| <span class="comment">// Unless this is an iterator terminal, use the</span> |
| <span class="comment">// default evaluation context</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">EnableIf</span> <span class="special">=</span> <span class="keyword">void</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">null_eval</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">IncrementCtx</span> <span class="keyword">const</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// advance iterator terminals.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">eval</span><span class="special"><</span> |
| <span class="identifier">Expr</span> |
| <span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">enable_if</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">iterator_wrapper</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> <span class="special">></span> <span class="special">></span> |
| <span class="special">>::</span><span class="identifier">type</span> |
| <span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">void</span> <span class="identifier">result_type</span><span class="special">;</span> |
| |
| <span class="identifier">result_type</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">Expr</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">IncrementCtx</span> <span class="keyword">const</span> <span class="special">&)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="special">++</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">value</span><span class="special">(</span><span class="identifier">expr</span><span class="special">).</span><span class="identifier">it</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// A grammar which matches all the assignment operators,</span> |
| <span class="comment">// so we can easily disable them.</span> |
| <span class="keyword">struct</span> <span class="identifier">AssignOps</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">switch_</span><span class="special"><</span><span class="keyword">struct</span> <span class="identifier">AssignOpsCases</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Here are the cases used by the switch_ above.</span> |
| <span class="keyword">struct</span> <span class="identifier">AssignOpsCases</span> |
| <span class="special">{</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Tag</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">D</span> <span class="special">=</span> <span class="number">0</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span> <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">not_</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">plus_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">minus_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">multiplies_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">divides_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">modulus_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">shift_left_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">shift_right_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">bitwise_and_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">bitwise_or_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">int</span> <span class="identifier">D</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">case_</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">bitwise_xor_assign</span><span class="special">,</span> <span class="identifier">D</span> <span class="special">></span> <span class="special">:</span> <span class="identifier">_</span> <span class="special">{};</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// An expression conforms to the MixedGrammar if it is a terminal or some</span> |
| <span class="comment">// op that is not an assignment op. (Assignment will be handled specially.)</span> |
| <span class="keyword">struct</span> <span class="identifier">MixedGrammar</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">and_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">nary_expr</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">vararg</span><span class="special"><</span><span class="identifier">MixedGrammar</span><span class="special">></span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">not_</span><span class="special"><</span><span class="identifier">AssignOps</span><span class="special">></span> |
| <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Expressions in the MixedDomain will be wrapped in MixedExpr<></span> |
| <span class="comment">// and must conform to the MixedGrammar</span> |
| <span class="keyword">struct</span> <span class="identifier">MixedDomain</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">generator</span><span class="special"><</span><span class="identifier">MixedExpr</span><span class="special">>,</span> <span class="identifier">MixedGrammar</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Here is MixedExpr, a wrapper for expression types in the MixedDomain.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">MixedExpr</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">MixedExpr</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>,</span> <span class="identifier">MixedDomain</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">explicit</span> <span class="identifier">MixedExpr</span><span class="special">(</span><span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">MixedExpr</span><span class="special">::</span><span class="identifier">proto_extends</span><span class="special">(</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{}</span> |
| <span class="keyword">private</span><span class="special">:</span> |
| <span class="comment">// hide this:</span> |
| <span class="keyword">using</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">MixedExpr</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">>,</span> <span class="identifier">MixedDomain</span><span class="special">>::</span><span class="keyword">operator</span> <span class="special">[];</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Define a trait type for detecting vector and list terminals, to</span> |
| <span class="comment">// be used by the BOOST_PROTO_DEFINE_OPERATORS macro below.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">IsMixed</span> |
| <span class="special">:</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">false_</span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">IsMixed</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">></span> |
| <span class="special">:</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">true_</span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">IsMixed</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">></span> |
| <span class="special">:</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">true_</span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">namespace</span> <span class="identifier">MixedOps</span> |
| <span class="special">{</span> |
| <span class="comment">// This defines all the overloads to make expressions involving</span> |
| <span class="comment">// std::vector to build expression templates.</span> |
| <span class="identifier">BOOST_PROTO_DEFINE_OPERATORS</span><span class="special">(</span><span class="identifier">IsMixed</span><span class="special">,</span> <span class="identifier">MixedDomain</span><span class="special">)</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">assign_op</span> |
| <span class="special">{</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">U</span><span class="special">></span> |
| <span class="keyword">void</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">T</span> <span class="special">&</span><span class="identifier">t</span><span class="special">,</span> <span class="identifier">U</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">u</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">t</span> <span class="special">=</span> <span class="identifier">u</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">plus_assign_op</span> |
| <span class="special">{</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">U</span><span class="special">></span> |
| <span class="keyword">void</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">T</span> <span class="special">&</span><span class="identifier">t</span><span class="special">,</span> <span class="identifier">U</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">u</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">t</span> <span class="special">+=</span> <span class="identifier">u</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">minus_assign_op</span> |
| <span class="special">{</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">U</span><span class="special">></span> |
| <span class="keyword">void</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">T</span> <span class="special">&</span><span class="identifier">t</span><span class="special">,</span> <span class="identifier">U</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">u</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">t</span> <span class="special">-=</span> <span class="identifier">u</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">sin_</span> |
| <span class="special">{</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Sig</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">result</span><span class="special">;</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">This</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Arg</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">result</span><span class="special"><</span><span class="identifier">This</span><span class="special">(</span><span class="identifier">Arg</span><span class="special">)></span> |
| <span class="special">:</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">remove_const</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">remove_reference</span><span class="special"><</span><span class="identifier">Arg</span><span class="special">>::</span><span class="identifier">type</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Arg</span><span class="special">></span> |
| <span class="identifier">Arg</span> <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">Arg</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">a</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">sin</span><span class="special">(</span><span class="identifier">a</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">A</span><span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">make_expr</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">function</span> |
| <span class="special">,</span> <span class="identifier">MixedDomain</span> |
| <span class="special">,</span> <span class="identifier">sin_</span> <span class="keyword">const</span> |
| <span class="special">,</span> <span class="identifier">A</span> <span class="keyword">const</span> <span class="special">&</span> |
| <span class="special">>::</span><span class="identifier">type</span> <span class="identifier">sin</span><span class="special">(</span><span class="identifier">A</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">a</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">make_expr</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">function</span><span class="special">,</span> <span class="identifier">MixedDomain</span><span class="special">>(</span><span class="identifier">sin_</span><span class="special">(),</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">a</span><span class="special">));</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">FwdIter</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Op</span><span class="special">></span> |
| <span class="keyword">void</span> <span class="identifier">evaluate</span><span class="special">(</span><span class="identifier">FwdIter</span> <span class="identifier">begin</span><span class="special">,</span> <span class="identifier">FwdIter</span> <span class="identifier">end</span><span class="special">,</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">,</span> <span class="identifier">Op</span> <span class="identifier">op</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">IncrementCtx</span> <span class="keyword">const</span> <span class="identifier">inc</span> <span class="special">=</span> <span class="special">{};</span> |
| <span class="identifier">DereferenceCtx</span> <span class="keyword">const</span> <span class="identifier">deref</span> <span class="special">=</span> <span class="special">{};</span> |
| <span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">result_of</span><span class="special"><</span><span class="identifier">Begin</span><span class="special">(</span><span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&)>::</span><span class="identifier">type</span> <span class="identifier">expr2</span> <span class="special">=</span> <span class="identifier">Begin</span><span class="special">()(</span><span class="identifier">expr</span><span class="special">);</span> |
| <span class="keyword">for</span><span class="special">(;</span> <span class="identifier">begin</span> <span class="special">!=</span> <span class="identifier">end</span><span class="special">;</span> <span class="special">++</span><span class="identifier">begin</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">op</span><span class="special">(*</span><span class="identifier">begin</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">expr2</span><span class="special">,</span> <span class="identifier">deref</span><span class="special">));</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(</span><span class="identifier">expr2</span><span class="special">,</span> <span class="identifier">inc</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">}</span> |
| |
| <span class="comment">// Add-assign to a vector from some expression.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">&</span><span class="identifier">assign</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">&</span><span class="identifier">arr</span><span class="special">,</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">evaluate</span><span class="special">(</span><span class="identifier">arr</span><span class="special">.</span><span class="identifier">begin</span><span class="special">(),</span> <span class="identifier">arr</span><span class="special">.</span><span class="identifier">end</span><span class="special">(),</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special"><</span><span class="identifier">MixedDomain</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">),</span> <span class="identifier">assign_op</span><span class="special">());</span> |
| <span class="keyword">return</span> <span class="identifier">arr</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="comment">// Add-assign to a list from some expression.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">&</span><span class="identifier">assign</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">&</span><span class="identifier">arr</span><span class="special">,</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">evaluate</span><span class="special">(</span><span class="identifier">arr</span><span class="special">.</span><span class="identifier">begin</span><span class="special">(),</span> <span class="identifier">arr</span><span class="special">.</span><span class="identifier">end</span><span class="special">(),</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special"><</span><span class="identifier">MixedDomain</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">),</span> <span class="identifier">assign_op</span><span class="special">());</span> |
| <span class="keyword">return</span> <span class="identifier">arr</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="comment">// Add-assign to a vector from some expression.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">+=(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">&</span><span class="identifier">arr</span><span class="special">,</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">evaluate</span><span class="special">(</span><span class="identifier">arr</span><span class="special">.</span><span class="identifier">begin</span><span class="special">(),</span> <span class="identifier">arr</span><span class="special">.</span><span class="identifier">end</span><span class="special">(),</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special"><</span><span class="identifier">MixedDomain</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">),</span> <span class="identifier">plus_assign_op</span><span class="special">());</span> |
| <span class="keyword">return</span> <span class="identifier">arr</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="comment">// Add-assign to a list from some expression.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">+=(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">&</span><span class="identifier">arr</span><span class="special">,</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">evaluate</span><span class="special">(</span><span class="identifier">arr</span><span class="special">.</span><span class="identifier">begin</span><span class="special">(),</span> <span class="identifier">arr</span><span class="special">.</span><span class="identifier">end</span><span class="special">(),</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special"><</span><span class="identifier">MixedDomain</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">),</span> <span class="identifier">plus_assign_op</span><span class="special">());</span> |
| <span class="keyword">return</span> <span class="identifier">arr</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="comment">// Minus-assign to a vector from some expression.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">-=(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">&</span><span class="identifier">arr</span><span class="special">,</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">evaluate</span><span class="special">(</span><span class="identifier">arr</span><span class="special">.</span><span class="identifier">begin</span><span class="special">(),</span> <span class="identifier">arr</span><span class="special">.</span><span class="identifier">end</span><span class="special">(),</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special"><</span><span class="identifier">MixedDomain</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">),</span> <span class="identifier">minus_assign_op</span><span class="special">());</span> |
| <span class="keyword">return</span> <span class="identifier">arr</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="comment">// Minus-assign to a list from some expression.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">&</span><span class="keyword">operator</span> <span class="special">-=(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">A</span><span class="special">></span> <span class="special">&</span><span class="identifier">arr</span><span class="special">,</span> <span class="identifier">Expr</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">expr</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">evaluate</span><span class="special">(</span><span class="identifier">arr</span><span class="special">.</span><span class="identifier">begin</span><span class="special">(),</span> <span class="identifier">arr</span><span class="special">.</span><span class="identifier">end</span><span class="special">(),</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special"><</span><span class="identifier">MixedDomain</span><span class="special">>(</span><span class="identifier">expr</span><span class="special">),</span> <span class="identifier">minus_assign_op</span><span class="special">());</span> |
| <span class="keyword">return</span> <span class="identifier">arr</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">MixedOps</span><span class="special">;</span> |
| |
| <span class="keyword">int</span> <span class="identifier">n</span> <span class="special">=</span> <span class="number">10</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="identifier">a</span><span class="special">,</span><span class="identifier">b</span><span class="special">,</span><span class="identifier">c</span><span class="special">,</span><span class="identifier">d</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span> <span class="identifier">e</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">complex</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span> <span class="special">></span> <span class="identifier">f</span><span class="special">;</span> |
| |
| <span class="keyword">int</span> <span class="identifier">i</span><span class="special">;</span> |
| <span class="keyword">for</span><span class="special">(</span><span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span><span class="identifier">i</span> <span class="special"><</span> <span class="identifier">n</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">a</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">i</span><span class="special">);</span> |
| <span class="identifier">b</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">2</span><span class="special">*</span><span class="identifier">i</span><span class="special">);</span> |
| <span class="identifier">c</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">3</span><span class="special">*</span><span class="identifier">i</span><span class="special">);</span> |
| <span class="identifier">d</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">i</span><span class="special">);</span> |
| <span class="identifier">e</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="number">0.0</span><span class="special">);</span> |
| <span class="identifier">f</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">complex</span><span class="special"><</span><span class="keyword">double</span><span class="special">>(</span><span class="number">1.0</span><span class="special">,</span> <span class="number">1.0</span><span class="special">));</span> |
| <span class="special">}</span> |
| |
| <span class="identifier">MixedOps</span><span class="special">::</span><span class="identifier">assign</span><span class="special">(</span><span class="identifier">b</span><span class="special">,</span> <span class="number">2</span><span class="special">);</span> |
| <span class="identifier">MixedOps</span><span class="special">::</span><span class="identifier">assign</span><span class="special">(</span><span class="identifier">d</span><span class="special">,</span> <span class="identifier">a</span> <span class="special">+</span> <span class="identifier">b</span> <span class="special">*</span> <span class="identifier">c</span><span class="special">);</span> |
| <span class="identifier">a</span> <span class="special">+=</span> <span class="identifier">if_else</span><span class="special">(</span><span class="identifier">d</span> <span class="special"><</span> <span class="number">30</span><span class="special">,</span> <span class="identifier">b</span><span class="special">,</span> <span class="identifier">c</span><span class="special">);</span> |
| |
| <span class="identifier">MixedOps</span><span class="special">::</span><span class="identifier">assign</span><span class="special">(</span><span class="identifier">e</span><span class="special">,</span> <span class="identifier">c</span><span class="special">);</span> |
| <span class="identifier">e</span> <span class="special">+=</span> <span class="identifier">e</span> <span class="special">-</span> <span class="number">4</span> <span class="special">/</span> <span class="special">(</span><span class="identifier">c</span> <span class="special">+</span> <span class="number">1</span><span class="special">);</span> |
| |
| <span class="identifier">f</span> <span class="special">-=</span> <span class="identifier">sin</span><span class="special">(</span><span class="number">0.1</span> <span class="special">*</span> <span class="identifier">e</span> <span class="special">*</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">complex</span><span class="special"><</span><span class="keyword">double</span><span class="special">>(</span><span class="number">0.2</span><span class="special">,</span> <span class="number">1.2</span><span class="special">));</span> |
| |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><</span><span class="keyword">double</span><span class="special">>::</span><span class="identifier">const_iterator</span> <span class="identifier">ei</span> <span class="special">=</span> <span class="identifier">e</span><span class="special">.</span><span class="identifier">begin</span><span class="special">();</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">complex</span><span class="special"><</span><span class="keyword">double</span><span class="special">></span> <span class="special">>::</span><span class="identifier">const_iterator</span> <span class="identifier">fi</span> <span class="special">=</span> <span class="identifier">f</span><span class="special">.</span><span class="identifier">begin</span><span class="special">();</span> |
| <span class="keyword">for</span> <span class="special">(</span><span class="identifier">i</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span> <span class="identifier">i</span> <span class="special"><</span> <span class="identifier">n</span><span class="special">;</span> <span class="special">++</span><span class="identifier">i</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> |
| <span class="special"><<</span> <span class="string">"a("</span> <span class="special"><<</span> <span class="identifier">i</span> <span class="special"><<</span> <span class="string">") = "</span> <span class="special"><<</span> <span class="identifier">a</span><span class="special">[</span><span class="identifier">i</span><span class="special">]</span> |
| <span class="special"><<</span> <span class="string">" b("</span> <span class="special"><<</span> <span class="identifier">i</span> <span class="special"><<</span> <span class="string">") = "</span> <span class="special"><<</span> <span class="identifier">b</span><span class="special">[</span><span class="identifier">i</span><span class="special">]</span> |
| <span class="special"><<</span> <span class="string">" c("</span> <span class="special"><<</span> <span class="identifier">i</span> <span class="special"><<</span> <span class="string">") = "</span> <span class="special"><<</span> <span class="identifier">c</span><span class="special">[</span><span class="identifier">i</span><span class="special">]</span> |
| <span class="special"><<</span> <span class="string">" d("</span> <span class="special"><<</span> <span class="identifier">i</span> <span class="special"><<</span> <span class="string">") = "</span> <span class="special"><<</span> <span class="identifier">d</span><span class="special">[</span><span class="identifier">i</span><span class="special">]</span> |
| <span class="special"><<</span> <span class="string">" e("</span> <span class="special"><<</span> <span class="identifier">i</span> <span class="special"><<</span> <span class="string">") = "</span> <span class="special"><<</span> <span class="special">*</span><span class="identifier">ei</span><span class="special">++</span> |
| <span class="special"><<</span> <span class="string">" f("</span> <span class="special"><<</span> <span class="identifier">i</span> <span class="special"><<</span> <span class="string">") = "</span> <span class="special"><<</span> <span class="special">*</span><span class="identifier">fi</span><span class="special">++</span> |
| <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.examples.map_assign"></a><a class="link" href="users_guide.html#boost_proto.users_guide.examples.map_assign" title="Map Assign: An Intermediate Transform">Map Assign: |
| An Intermediate Transform</a> |
| </h4></div></div></div> |
| <p> |
| A demonstration of how to implement <code class="computeroutput"><span class="identifier">map_list_of</span><span class="special">()</span></code> from the Boost.Assign library using Proto. |
| <code class="computeroutput"><span class="identifier">map_list_assign</span><span class="special">()</span></code> |
| is used to conveniently initialize a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">map</span><span class="special"><></span></code>. By using Proto, we can avoid any |
| dynamic allocation while building the intermediate representation. |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="comment">// Copyright 2008 Eric Niebler. Distributed under the Boost</span> |
| <span class="comment">// Software License, Version 1.0. (See accompanying file</span> |
| <span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span> |
| <span class="comment">//</span> |
| <span class="comment">// This is a port of map_list_of() from the Boost.Assign library.</span> |
| <span class="comment">// It has the advantage of being more efficient at runtime by not</span> |
| <span class="comment">// building any temporary container that requires dynamic allocation.</span> |
| |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">map</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">string</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">transform</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">type_traits</span><span class="special">/</span><span class="identifier">add_reference</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="keyword">namespace</span> <span class="identifier">proto</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">;</span> |
| <span class="keyword">using</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span><span class="special">;</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">map_list_of_tag</span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// A simple callable function object that inserts a</span> |
| <span class="comment">// (key,value) pair into a map.</span> |
| <span class="keyword">struct</span> <span class="identifier">insert</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable</span> |
| <span class="special">{</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Sig</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">result</span><span class="special">;</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">This</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Map</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Key</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Value</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">result</span><span class="special"><</span><span class="identifier">This</span><span class="special">(</span><span class="identifier">Map</span><span class="special">,</span> <span class="identifier">Key</span><span class="special">,</span> <span class="identifier">Value</span><span class="special">)></span> |
| <span class="special">:</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">add_reference</span><span class="special"><</span><span class="identifier">Map</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Map</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Key</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Value</span><span class="special">></span> |
| <span class="identifier">Map</span> <span class="special">&</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">Map</span> <span class="special">&</span><span class="identifier">map</span><span class="special">,</span> <span class="identifier">Key</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">key</span><span class="special">,</span> <span class="identifier">Value</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">value</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">map</span><span class="special">.</span><span class="identifier">insert</span><span class="special">(</span><span class="keyword">typename</span> <span class="identifier">Map</span><span class="special">::</span><span class="identifier">value_type</span><span class="special">(</span><span class="identifier">key</span><span class="special">,</span> <span class="identifier">value</span><span class="special">));</span> |
| <span class="keyword">return</span> <span class="identifier">map</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Work-arounds for Microsoft Visual C++ 7.1</span> |
| <span class="preprocessor">#if</span> <span class="identifier">BOOST_WORKAROUND</span><span class="special">(</span><span class="identifier">BOOST_MSVC</span><span class="special">,</span> <span class="special">==</span> <span class="number">1310</span><span class="special">)</span> |
| <span class="preprocessor">#define</span> <span class="identifier">MapListOf</span><span class="special">(</span><span class="identifier">x</span><span class="special">)</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">call</span><span class="special"><</span><span class="identifier">MapListOf</span><span class="special">(</span><span class="identifier">x</span><span class="special">)></span> |
| <span class="preprocessor">#define</span> <span class="identifier">_value</span><span class="special">(</span><span class="identifier">x</span><span class="special">)</span> <span class="identifier">call</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">(</span><span class="identifier">x</span><span class="special">)></span> |
| <span class="preprocessor">#endif</span> |
| |
| <span class="comment">// The grammar for valid map-list expressions, and a</span> |
| <span class="comment">// transform that populates the map.</span> |
| <span class="keyword">struct</span> <span class="identifier">MapListOf</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">function</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">map_list_of_tag</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> |
| <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">insert</span><span class="special">(</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_data</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child1</span><span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child2</span><span class="special">)</span> |
| <span class="special">)</span> |
| <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">function</span><span class="special"><</span> |
| <span class="identifier">MapListOf</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> |
| <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">insert</span><span class="special">(</span> |
| <span class="identifier">MapListOf</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child0</span><span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child1</span><span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_child2</span><span class="special">)</span> |
| <span class="special">)</span> |
| <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="preprocessor">#if</span> <span class="identifier">BOOST_WORKAROUND</span><span class="special">(</span><span class="identifier">BOOST_MSVC</span><span class="special">,</span> <span class="special">==</span> <span class="number">1310</span><span class="special">)</span> |
| <span class="preprocessor">#undef</span> <span class="identifier">MapListOf</span> |
| <span class="preprocessor">#undef</span> <span class="identifier">_value</span> |
| <span class="preprocessor">#endif</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">map_list_of_expr</span><span class="special">;</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">map_list_of_dom</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">pod_generator</span><span class="special"><</span><span class="identifier">map_list_of_expr</span><span class="special">>,</span> <span class="identifier">MapListOf</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// An expression wrapper that provides a conversion to a</span> |
| <span class="comment">// map that uses the MapListOf</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Expr</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">map_list_of_expr</span> |
| <span class="special">{</span> |
| <span class="identifier">BOOST_PROTO_BASIC_EXTENDS</span><span class="special">(</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">map_list_of_expr</span><span class="special">,</span> <span class="identifier">map_list_of_dom</span><span class="special">)</span> |
| <span class="identifier">BOOST_PROTO_EXTENDS_FUNCTION</span><span class="special">()</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Key</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Value</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Cmp</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Al</span><span class="special">></span> |
| <span class="keyword">operator</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">map</span><span class="special"><</span><span class="identifier">Key</span><span class="special">,</span> <span class="identifier">Value</span><span class="special">,</span> <span class="identifier">Cmp</span><span class="special">,</span> <span class="identifier">Al</span><span class="special">></span> <span class="special">()</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">BOOST_MPL_ASSERT</span><span class="special">((</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><</span><span class="identifier">Expr</span><span class="special">,</span> <span class="identifier">MapListOf</span><span class="special">>));</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">map</span><span class="special"><</span><span class="identifier">Key</span><span class="special">,</span> <span class="identifier">Value</span><span class="special">,</span> <span class="identifier">Cmp</span><span class="special">,</span> <span class="identifier">Al</span><span class="special">></span> <span class="identifier">map</span><span class="special">;</span> |
| <span class="keyword">return</span> <span class="identifier">MapListOf</span><span class="special">()(*</span><span class="keyword">this</span><span class="special">,</span> <span class="number">0</span><span class="special">,</span> <span class="identifier">map</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="identifier">map_list_of_expr</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">map_list_of_tag</span><span class="special">>::</span><span class="identifier">type</span><span class="special">></span> <span class="keyword">const</span> <span class="identifier">map_list_of</span> <span class="special">=</span> <span class="special">{{{}}};</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="comment">// Initialize a map:</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">map</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">,</span> <span class="keyword">int</span><span class="special">></span> <span class="identifier">op</span> <span class="special">=</span> |
| <span class="identifier">map_list_of</span> |
| <span class="special">(</span><span class="string">"<"</span><span class="special">,</span> <span class="number">1</span><span class="special">)</span> |
| <span class="special">(</span><span class="string">"<="</span><span class="special">,</span><span class="number">2</span><span class="special">)</span> |
| <span class="special">(</span><span class="string">">"</span><span class="special">,</span> <span class="number">3</span><span class="special">)</span> |
| <span class="special">(</span><span class="string">">="</span><span class="special">,</span><span class="number">4</span><span class="special">)</span> |
| <span class="special">(</span><span class="string">"="</span><span class="special">,</span> <span class="number">5</span><span class="special">)</span> |
| <span class="special">(</span><span class="string">"<>"</span><span class="special">,</span><span class="number">6</span><span class="special">)</span> |
| <span class="special">;</span> |
| |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"\"<\" --> "</span> <span class="special"><<</span> <span class="identifier">op</span><span class="special">[</span><span class="string">"<"</span><span class="special">]</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"\"<=\" --> "</span> <span class="special"><<</span> <span class="identifier">op</span><span class="special">[</span><span class="string">"<="</span><span class="special">]</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"\">\" --> "</span> <span class="special"><<</span> <span class="identifier">op</span><span class="special">[</span><span class="string">">"</span><span class="special">]</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"\">=\" --> "</span> <span class="special"><<</span> <span class="identifier">op</span><span class="special">[</span><span class="string">">="</span><span class="special">]</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"\"=\" --> "</span> <span class="special"><<</span> <span class="identifier">op</span><span class="special">[</span><span class="string">"="</span><span class="special">]</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"\"<>\" --> "</span> <span class="special"><<</span> <span class="identifier">op</span><span class="special">[</span><span class="string">"<>"</span><span class="special">]</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> |
| |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.examples.future_group"></a><a class="link" href="users_guide.html#boost_proto.users_guide.examples.future_group" title="Future Group: A More Advanced Transform">Future |
| Group: A More Advanced Transform</a> |
| </h4></div></div></div> |
| <p> |
| An advanced example of a Proto transform that implements Howard Hinnant's |
| design for <span class="emphasis"><em>future groups</em></span> that block for all or some |
| asynchronous operations to complete and returns their results in a tuple |
| of the appropriate type. |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="comment">// Copyright 2008 Eric Niebler. Distributed under the Boost</span> |
| <span class="comment">// Software License, Version 1.0. (See accompanying file</span> |
| <span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span> |
| <span class="comment">//</span> |
| <span class="comment">// This is an example of using Proto transforms to implement</span> |
| <span class="comment">// Howard Hinnant's future group proposal.</span> |
| |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">fusion</span><span class="special">/</span><span class="identifier">include</span><span class="special">/</span><span class="identifier">vector</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">fusion</span><span class="special">/</span><span class="identifier">include</span><span class="special">/</span><span class="identifier">as_vector</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">fusion</span><span class="special">/</span><span class="identifier">include</span><span class="special">/</span><span class="identifier">joint_view</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">fusion</span><span class="special">/</span><span class="identifier">include</span><span class="special">/</span><span class="identifier">single_view</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">transform</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="keyword">namespace</span> <span class="identifier">mpl</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">mpl</span><span class="special">;</span> |
| <span class="keyword">namespace</span> <span class="identifier">proto</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">;</span> |
| <span class="keyword">namespace</span> <span class="identifier">fusion</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fusion</span><span class="special">;</span> |
| <span class="keyword">using</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span><span class="special">;</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">L</span><span class="special">,</span><span class="keyword">class</span> <span class="identifier">R</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">pick_left</span> |
| <span class="special">{</span> |
| <span class="identifier">BOOST_MPL_ASSERT</span><span class="special">((</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">is_same</span><span class="special"><</span><span class="identifier">L</span><span class="special">,</span> <span class="identifier">R</span><span class="special">>));</span> |
| <span class="keyword">typedef</span> <span class="identifier">L</span> <span class="identifier">type</span><span class="special">;</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Work-arounds for Microsoft Visual C++ 7.1</span> |
| <span class="preprocessor">#if</span> <span class="identifier">BOOST_WORKAROUND</span><span class="special">(</span><span class="identifier">BOOST_MSVC</span><span class="special">,</span> <span class="special">==</span> <span class="number">1310</span><span class="special">)</span> |
| <span class="preprocessor">#define</span> <span class="identifier">FutureGroup</span><span class="special">(</span><span class="identifier">x</span><span class="special">)</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">call</span><span class="special"><</span><span class="identifier">FutureGroup</span><span class="special">(</span><span class="identifier">x</span><span class="special">)></span> |
| <span class="preprocessor">#endif</span> |
| |
| <span class="comment">// Define the grammar of future group expression, as well as a</span> |
| <span class="comment">// transform to turn them into a Fusion sequence of the correct</span> |
| <span class="comment">// type.</span> |
| <span class="keyword">struct</span> <span class="identifier">FutureGroup</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="comment">// terminals become a single-element Fusion sequence</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">single_view</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">>(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">)</span> |
| <span class="special">></span> |
| <span class="comment">// (a && b) becomes a concatenation of the sequence</span> |
| <span class="comment">// from 'a' and the one from 'b':</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">logical_and</span><span class="special"><</span><span class="identifier">FutureGroup</span><span class="special">,</span> <span class="identifier">FutureGroup</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">joint_view</span><span class="special"><</span> |
| <span class="identifier">boost</span><span class="special">::</span><span class="identifier">add_const</span><span class="special"><</span><span class="identifier">FutureGroup</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_left</span><span class="special">)</span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">add_const</span><span class="special"><</span><span class="identifier">FutureGroup</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_right</span><span class="special">)</span> <span class="special">></span> |
| <span class="special">>(</span><span class="identifier">FutureGroup</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_left</span><span class="special">),</span> <span class="identifier">FutureGroup</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_right</span><span class="special">))</span> |
| <span class="special">></span> |
| <span class="comment">// (a || b) becomes the sequence for 'a', so long</span> |
| <span class="comment">// as it is the same as the sequence for 'b'.</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">logical_or</span><span class="special"><</span><span class="identifier">FutureGroup</span><span class="special">,</span> <span class="identifier">FutureGroup</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">pick_left</span><span class="special"><</span> |
| <span class="identifier">FutureGroup</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_left</span><span class="special">)</span> |
| <span class="special">,</span> <span class="identifier">FutureGroup</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_right</span><span class="special">)</span> |
| <span class="special">>(</span><span class="identifier">FutureGroup</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_left</span><span class="special">))</span> |
| <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="preprocessor">#if</span> <span class="identifier">BOOST_WORKAROUND</span><span class="special">(</span><span class="identifier">BOOST_MSVC</span><span class="special">,</span> <span class="special">==</span> <span class="number">1310</span><span class="special">)</span> |
| <span class="preprocessor">#undef</span> <span class="identifier">FutureGroup</span> |
| <span class="preprocessor">#endif</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">E</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">future_expr</span><span class="special">;</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">future_dom</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">generator</span><span class="special"><</span><span class="identifier">future_expr</span><span class="special">>,</span> <span class="identifier">FutureGroup</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Expressions in the future group domain have a .get()</span> |
| <span class="comment">// member function that (ostensibly) blocks for the futures</span> |
| <span class="comment">// to complete and returns the results in an appropriate</span> |
| <span class="comment">// tuple.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">E</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">future_expr</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><</span><span class="identifier">E</span><span class="special">,</span> <span class="identifier">future_expr</span><span class="special"><</span><span class="identifier">E</span><span class="special">>,</span> <span class="identifier">future_dom</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="keyword">explicit</span> <span class="identifier">future_expr</span><span class="special">(</span><span class="identifier">E</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">e</span><span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">future_expr</span><span class="special">::</span><span class="identifier">proto_extends</span><span class="special">(</span><span class="identifier">e</span><span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="keyword">typename</span> <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">as_vector</span><span class="special"><</span> |
| <span class="keyword">typename</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">result_of</span><span class="special"><</span><span class="identifier">FutureGroup</span><span class="special">(</span><span class="identifier">E</span><span class="special">)>::</span><span class="identifier">type</span> |
| <span class="special">>::</span><span class="identifier">type</span> |
| <span class="identifier">get</span><span class="special">()</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">as_vector</span><span class="special">(</span><span class="identifier">FutureGroup</span><span class="special">()(*</span><span class="keyword">this</span><span class="special">));</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// The future<> type has an even simpler .get()</span> |
| <span class="comment">// member function.</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">future</span> |
| <span class="special">:</span> <span class="identifier">future_expr</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">T</span><span class="special">>::</span><span class="identifier">type</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="identifier">future</span><span class="special">(</span><span class="identifier">T</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">t</span> <span class="special">=</span> <span class="identifier">T</span><span class="special">())</span> |
| <span class="special">:</span> <span class="identifier">future</span><span class="special">::</span><span class="identifier">proto_derived_expr</span><span class="special">(</span><span class="identifier">future</span><span class="special">::</span><span class="identifier">proto_base_expr</span><span class="special">::</span><span class="identifier">make</span><span class="special">(</span><span class="identifier">t</span><span class="special">))</span> |
| <span class="special">{}</span> |
| |
| <span class="identifier">T</span> <span class="identifier">get</span><span class="special">()</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">value</span><span class="special">(*</span><span class="keyword">this</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// TEST CASES</span> |
| <span class="keyword">struct</span> <span class="identifier">A</span> <span class="special">{};</span> |
| <span class="keyword">struct</span> <span class="identifier">B</span> <span class="special">{};</span> |
| <span class="keyword">struct</span> <span class="identifier">C</span> <span class="special">{};</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="keyword">using</span> <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">vector</span><span class="special">;</span> |
| <span class="identifier">future</span><span class="special"><</span><span class="identifier">A</span><span class="special">></span> <span class="identifier">a</span><span class="special">;</span> |
| <span class="identifier">future</span><span class="special"><</span><span class="identifier">B</span><span class="special">></span> <span class="identifier">b</span><span class="special">;</span> |
| <span class="identifier">future</span><span class="special"><</span><span class="identifier">C</span><span class="special">></span> <span class="identifier">c</span><span class="special">;</span> |
| <span class="identifier">future</span><span class="special"><</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">A</span><span class="special">,</span><span class="identifier">B</span><span class="special">></span> <span class="special">></span> <span class="identifier">ab</span><span class="special">;</span> |
| |
| <span class="comment">// Verify that various future groups have the</span> |
| <span class="comment">// correct return types.</span> |
| <span class="identifier">A</span> <span class="identifier">t0</span> <span class="special">=</span> <span class="identifier">a</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span> |
| <span class="identifier">vector</span><span class="special"><</span><span class="identifier">A</span><span class="special">,</span> <span class="identifier">B</span><span class="special">,</span> <span class="identifier">C</span><span class="special">></span> <span class="identifier">t1</span> <span class="special">=</span> <span class="special">(</span><span class="identifier">a</span> <span class="special">&&</span> <span class="identifier">b</span> <span class="special">&&</span> <span class="identifier">c</span><span class="special">).</span><span class="identifier">get</span><span class="special">();</span> |
| <span class="identifier">vector</span><span class="special"><</span><span class="identifier">A</span><span class="special">,</span> <span class="identifier">C</span><span class="special">></span> <span class="identifier">t2</span> <span class="special">=</span> <span class="special">((</span><span class="identifier">a</span> <span class="special">||</span> <span class="identifier">a</span><span class="special">)</span> <span class="special">&&</span> <span class="identifier">c</span><span class="special">).</span><span class="identifier">get</span><span class="special">();</span> |
| <span class="identifier">vector</span><span class="special"><</span><span class="identifier">A</span><span class="special">,</span> <span class="identifier">B</span><span class="special">,</span> <span class="identifier">C</span><span class="special">></span> <span class="identifier">t3</span> <span class="special">=</span> <span class="special">((</span><span class="identifier">a</span> <span class="special">&&</span> <span class="identifier">b</span> <span class="special">||</span> <span class="identifier">a</span> <span class="special">&&</span> <span class="identifier">b</span><span class="special">)</span> <span class="special">&&</span> <span class="identifier">c</span><span class="special">).</span><span class="identifier">get</span><span class="special">();</span> |
| <span class="identifier">vector</span><span class="special"><</span><span class="identifier">vector</span><span class="special"><</span><span class="identifier">A</span><span class="special">,</span> <span class="identifier">B</span><span class="special">>,</span> <span class="identifier">C</span><span class="special">></span> <span class="identifier">t4</span> <span class="special">=</span> <span class="special">((</span><span class="identifier">ab</span> <span class="special">||</span> <span class="identifier">ab</span><span class="special">)</span> <span class="special">&&</span> <span class="identifier">c</span><span class="special">).</span><span class="identifier">get</span><span class="special">();</span> |
| |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h4 class="title"> |
| <a name="boost_proto.users_guide.examples.lambda"></a><a class="link" href="users_guide.html#boost_proto.users_guide.examples.lambda" title="Lambda: A Simple Lambda Library with Proto">Lambda: A |
| Simple Lambda Library with Proto</a> |
| </h4></div></div></div> |
| <p> |
| This is an advanced example that shows how to implement a simple lambda |
| DSEL with Proto, like the Boost.Lambda_library. It uses contexts, transforms |
| and expression extension. |
| </p> |
| <p> |
| |
| </p> |
| <pre class="programlisting"><span class="comment">///////////////////////////////////////////////////////////////////////////////</span> |
| <span class="comment">// Copyright 2008 Eric Niebler. Distributed under the Boost</span> |
| <span class="comment">// Software License, Version 1.0. (See accompanying file</span> |
| <span class="comment">// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)</span> |
| <span class="comment">//</span> |
| <span class="comment">// This example builds a simple but functional lambda library using Proto.</span> |
| |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">algorithm</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mpl</span><span class="special">/</span><span class="keyword">int</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mpl</span><span class="special">/</span><span class="identifier">min_max</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mpl</span><span class="special">/</span><span class="identifier">eval_if</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mpl</span><span class="special">/</span><span class="identifier">identity</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">mpl</span><span class="special">/</span><span class="identifier">next_prior</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">fusion</span><span class="special">/</span><span class="identifier">tuple</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">typeof</span><span class="special">/</span><span class="identifier">typeof</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">typeof</span><span class="special">/</span><span class="identifier">std</span><span class="special">/</span><span class="identifier">ostream</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">typeof</span><span class="special">/</span><span class="identifier">std</span><span class="special">/</span><span class="identifier">iostream</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">context</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">proto</span><span class="special">/</span><span class="identifier">transform</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> |
| <span class="keyword">namespace</span> <span class="identifier">mpl</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">mpl</span><span class="special">;</span> |
| <span class="keyword">namespace</span> <span class="identifier">proto</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">;</span> |
| <span class="keyword">namespace</span> <span class="identifier">fusion</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fusion</span><span class="special">;</span> |
| <span class="keyword">using</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span><span class="special">;</span> |
| |
| <span class="comment">// Forward declaration of the lambda expression wrapper</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">lambda</span><span class="special">;</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">lambda_domain</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">pod_generator</span><span class="special"><</span><span class="identifier">lambda</span><span class="special">></span> <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">I</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">placeholder</span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="identifier">I</span> <span class="identifier">arity</span><span class="special">;</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">placeholder_arity</span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="keyword">typename</span> <span class="identifier">T</span><span class="special">::</span><span class="identifier">arity</span> <span class="identifier">type</span><span class="special">;</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// The lambda grammar, with the transforms for calculating the max arity</span> |
| <span class="keyword">struct</span> <span class="identifier">lambda_arity</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">next</span><span class="special"><</span><span class="identifier">placeholder_arity</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">></span> <span class="special">>()</span> |
| <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> |
| <span class="special">,</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">int_</span><span class="special"><</span><span class="number">0</span><span class="special">>()</span> |
| <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">nary_expr</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">vararg</span><span class="special"><</span><span class="identifier">_</span><span class="special">></span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">fold</span><span class="special"><</span><span class="identifier">_</span><span class="special">,</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">int_</span><span class="special"><</span><span class="number">0</span><span class="special">>(),</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">max</span><span class="special"><</span><span class="identifier">lambda_arity</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_state</span><span class="special">>()></span> |
| <span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// The lambda context is the same as the default context</span> |
| <span class="comment">// with the addition of special handling for lambda placeholders</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Tuple</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">lambda_context</span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">callable_context</span><span class="special"><</span><span class="identifier">lambda_context</span><span class="special"><</span><span class="identifier">Tuple</span><span class="special">></span> <span class="keyword">const</span><span class="special">></span> |
| <span class="special">{</span> |
| <span class="identifier">lambda_context</span><span class="special">(</span><span class="identifier">Tuple</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">args</span><span class="special">)</span> |
| <span class="special">:</span> <span class="identifier">args_</span><span class="special">(</span><span class="identifier">args</span><span class="special">)</span> |
| <span class="special">{}</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Sig</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">result</span><span class="special">;</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">This</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">I</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">result</span><span class="special"><</span><span class="identifier">This</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">,</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="identifier">I</span><span class="special">></span> <span class="keyword">const</span> <span class="special">&)></span> |
| <span class="special">:</span> <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">at</span><span class="special"><</span><span class="identifier">Tuple</span><span class="special">,</span> <span class="identifier">I</span><span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">I</span><span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">at</span><span class="special"><</span><span class="identifier">Tuple</span><span class="special">,</span> <span class="identifier">I</span><span class="special">>::</span><span class="identifier">type</span> |
| <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">terminal</span><span class="special">,</span> <span class="identifier">placeholder</span><span class="special"><</span><span class="identifier">I</span><span class="special">></span> <span class="keyword">const</span> <span class="special">&)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="keyword">return</span> <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">at</span><span class="special"><</span><span class="identifier">I</span><span class="special">>(</span><span class="keyword">this</span><span class="special">-></span><span class="identifier">args_</span><span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="identifier">Tuple</span> <span class="identifier">args_</span><span class="special">;</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// The lambda<> expression wrapper makes expressions polymorphic</span> |
| <span class="comment">// function objects</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">lambda</span> |
| <span class="special">{</span> |
| <span class="identifier">BOOST_PROTO_BASIC_EXTENDS</span><span class="special">(</span><span class="identifier">T</span><span class="special">,</span> <span class="identifier">lambda</span><span class="special"><</span><span class="identifier">T</span><span class="special">>,</span> <span class="identifier">lambda_domain</span><span class="special">)</span> |
| <span class="identifier">BOOST_PROTO_EXTENDS_ASSIGN</span><span class="special">()</span> |
| <span class="identifier">BOOST_PROTO_EXTENDS_SUBSCRIPT</span><span class="special">()</span> |
| |
| <span class="comment">// Calculate the arity of this lambda expression</span> |
| <span class="keyword">static</span> <span class="keyword">int</span> <span class="keyword">const</span> <span class="identifier">arity</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">result_of</span><span class="special"><</span><span class="identifier">lambda_arity</span><span class="special">(</span><span class="identifier">T</span><span class="special">)>::</span><span class="identifier">type</span><span class="special">::</span><span class="identifier">value</span><span class="special">;</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Sig</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">result</span><span class="special">;</span> |
| |
| <span class="comment">// Define nested result<> specializations to calculate the return</span> |
| <span class="comment">// type of this lambda expression. But be careful not to evaluate</span> |
| <span class="comment">// the return type of the nullary function unless we have a nullary</span> |
| <span class="comment">// lambda!</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">This</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">result</span><span class="special"><</span><span class="identifier">This</span><span class="special">()></span> |
| <span class="special">:</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">eval_if_c</span><span class="special"><</span> |
| <span class="number">0</span> <span class="special">==</span> <span class="identifier">arity</span> |
| <span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">eval</span><span class="special"><</span><span class="identifier">T</span> <span class="keyword">const</span><span class="special">,</span> <span class="identifier">lambda_context</span><span class="special"><</span><span class="identifier">fusion</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><></span> <span class="special">></span> <span class="special">></span> |
| <span class="special">,</span> <span class="identifier">mpl</span><span class="special">::</span><span class="identifier">identity</span><span class="special"><</span><span class="keyword">void</span><span class="special">></span> |
| <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">This</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A0</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">result</span><span class="special"><</span><span class="identifier">This</span><span class="special">(</span><span class="identifier">A0</span><span class="special">)></span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">eval</span><span class="special"><</span><span class="identifier">T</span> <span class="keyword">const</span><span class="special">,</span> <span class="identifier">lambda_context</span><span class="special"><</span><span class="identifier">fusion</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><</span><span class="identifier">A0</span><span class="special">></span> <span class="special">></span> <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">This</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A0</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A1</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">result</span><span class="special"><</span><span class="identifier">This</span><span class="special">(</span><span class="identifier">A0</span><span class="special">,</span> <span class="identifier">A1</span><span class="special">)></span> |
| <span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">eval</span><span class="special"><</span><span class="identifier">T</span> <span class="keyword">const</span><span class="special">,</span> <span class="identifier">lambda_context</span><span class="special"><</span><span class="identifier">fusion</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><</span><span class="identifier">A0</span><span class="special">,</span> <span class="identifier">A1</span><span class="special">></span> <span class="special">></span> <span class="special">></span> |
| <span class="special">{};</span> |
| |
| <span class="comment">// Define our operator () that evaluates the lambda expression.</span> |
| <span class="keyword">typename</span> <span class="identifier">result</span><span class="special"><</span><span class="identifier">lambda</span><span class="special">()>::</span><span class="identifier">type</span> |
| <span class="keyword">operator</span> <span class="special">()()</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><></span> <span class="identifier">args</span><span class="special">;</span> |
| <span class="identifier">lambda_context</span><span class="special"><</span><span class="identifier">fusion</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><></span> <span class="special">></span> <span class="identifier">ctx</span><span class="special">(</span><span class="identifier">args</span><span class="special">);</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">A0</span><span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">result</span><span class="special"><</span><span class="identifier">lambda</span><span class="special">(</span><span class="identifier">A0</span> <span class="keyword">const</span> <span class="special">&)>::</span><span class="identifier">type</span> |
| <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">A0</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">a0</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><</span><span class="identifier">A0</span> <span class="keyword">const</span> <span class="special">&></span> <span class="identifier">args</span><span class="special">(</span><span class="identifier">a0</span><span class="special">);</span> |
| <span class="identifier">lambda_context</span><span class="special"><</span><span class="identifier">fusion</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><</span><span class="identifier">A0</span> <span class="keyword">const</span> <span class="special">&></span> <span class="special">></span> <span class="identifier">ctx</span><span class="special">(</span><span class="identifier">args</span><span class="special">);</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">A0</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">A1</span><span class="special">></span> |
| <span class="keyword">typename</span> <span class="identifier">result</span><span class="special"><</span><span class="identifier">lambda</span><span class="special">(</span><span class="identifier">A0</span> <span class="keyword">const</span> <span class="special">&,</span> <span class="identifier">A1</span> <span class="keyword">const</span> <span class="special">&)>::</span><span class="identifier">type</span> |
| <span class="keyword">operator</span> <span class="special">()(</span><span class="identifier">A0</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">a0</span><span class="special">,</span> <span class="identifier">A1</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">a1</span><span class="special">)</span> <span class="keyword">const</span> |
| <span class="special">{</span> |
| <span class="identifier">fusion</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><</span><span class="identifier">A0</span> <span class="keyword">const</span> <span class="special">&,</span> <span class="identifier">A1</span> <span class="keyword">const</span> <span class="special">&></span> <span class="identifier">args</span><span class="special">(</span><span class="identifier">a0</span><span class="special">,</span> <span class="identifier">a1</span><span class="special">);</span> |
| <span class="identifier">lambda_context</span><span class="special"><</span><span class="identifier">fusion</span><span class="special">::</span><span class="identifier">tuple</span><span class="special"><</span><span class="identifier">A0</span> <span class="keyword">const</span> <span class="special">&,</span> <span class="identifier">A1</span> <span class="keyword">const</span> <span class="special">&></span> <span class="special">></span> <span class="identifier">ctx</span><span class="special">(</span><span class="identifier">args</span><span class="special">);</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">(*</span><span class="keyword">this</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Define some lambda placeholders</span> |
| <span class="identifier">lambda</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">placeholder</span><span class="special"><</span><span class="identifier">mpl</span><span class="special">::</span><span class="identifier">int_</span><span class="special"><</span><span class="number">0</span><span class="special">></span> <span class="special">></span> <span class="special">>::</span><span class="identifier">type</span><span class="special">></span> <span class="keyword">const</span> <span class="identifier">_1</span> <span class="special">=</span> <span class="special">{{}};</span> |
| <span class="identifier">lambda</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">placeholder</span><span class="special"><</span><span class="identifier">mpl</span><span class="special">::</span><span class="identifier">int_</span><span class="special"><</span><span class="number">1</span><span class="special">></span> <span class="special">></span> <span class="special">>::</span><span class="identifier">type</span><span class="special">></span> <span class="keyword">const</span> <span class="identifier">_2</span> <span class="special">=</span> <span class="special">{{}};</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">></span> |
| <span class="identifier">lambda</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">T</span><span class="special">>::</span><span class="identifier">type</span><span class="special">></span> <span class="keyword">const</span> <span class="identifier">val</span><span class="special">(</span><span class="identifier">T</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">t</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">lambda</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">T</span><span class="special">>::</span><span class="identifier">type</span><span class="special">></span> <span class="identifier">that</span> <span class="special">=</span> <span class="special">{{</span><span class="identifier">t</span><span class="special">}};</span> |
| <span class="keyword">return</span> <span class="identifier">that</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">></span> |
| <span class="identifier">lambda</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">T</span> <span class="special">&>::</span><span class="identifier">type</span><span class="special">></span> <span class="keyword">const</span> <span class="identifier">var</span><span class="special">(</span><span class="identifier">T</span> <span class="special">&</span><span class="identifier">t</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">lambda</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span><span class="identifier">T</span> <span class="special">&>::</span><span class="identifier">type</span><span class="special">></span> <span class="identifier">that</span> <span class="special">=</span> <span class="special">{{</span><span class="identifier">t</span><span class="special">}};</span> |
| <span class="keyword">return</span> <span class="identifier">that</span><span class="special">;</span> |
| <span class="special">}</span> |
| |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">></span> |
| <span class="keyword">struct</span> <span class="identifier">construct_helper</span> |
| <span class="special">{</span> |
| <span class="keyword">typedef</span> <span class="identifier">T</span> <span class="identifier">result_type</span><span class="special">;</span> <span class="comment">// for TR1 result_of</span> |
| |
| <span class="identifier">T</span> <span class="keyword">operator</span><span class="special">()()</span> <span class="keyword">const</span> |
| <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">T</span><span class="special">();</span> <span class="special">}</span> |
| |
| <span class="comment">// Generate BOOST_PROTO_MAX_ARITY overloads of the</span> |
| <span class="comment">// followig function call operator.</span> |
| <span class="preprocessor">#define</span> <span class="identifier">BOOST_PROTO_LOCAL_MACRO</span><span class="special">(</span><span class="identifier">N</span><span class="special">,</span> <span class="identifier">typename_A</span><span class="special">,</span> <span class="identifier">A_const_ref</span><span class="special">,</span> <span class="identifier">A_const_ref_a</span><span class="special">,</span> <span class="identifier">a</span><span class="special">)\</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="identifier">typename_A</span><span class="special">(</span><span class="identifier">N</span><span class="special">)></span> <span class="special">\</span> |
| <span class="identifier">T</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">A_const_ref_a</span><span class="special">(</span><span class="identifier">N</span><span class="special">))</span> <span class="keyword">const</span> <span class="special">\</span> |
| <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">T</span><span class="special">(</span><span class="identifier">a</span><span class="special">(</span><span class="identifier">N</span><span class="special">));</span> <span class="special">}</span> |
| <span class="preprocessor">#define</span> <span class="identifier">BOOST_PROTO_LOCAL_a</span> <span class="identifier">BOOST_PROTO_a</span> |
| <span class="preprocessor">#include</span> <span class="identifier">BOOST_PROTO_LOCAL_ITERATE</span><span class="special">()</span> |
| <span class="special">};</span> |
| |
| <span class="comment">// Generate BOOST_PROTO_MAX_ARITY-1 overloads of the</span> |
| <span class="comment">// following construct() function template.</span> |
| <span class="preprocessor">#define</span> <span class="identifier">M0</span><span class="special">(</span><span class="identifier">N</span><span class="special">,</span> <span class="identifier">typename_A</span><span class="special">,</span> <span class="identifier">A_const_ref</span><span class="special">,</span> <span class="identifier">A_const_ref_a</span><span class="special">,</span> <span class="identifier">ref_a</span><span class="special">)</span> <span class="special">\</span> |
| <span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">typename_A</span><span class="special">(</span><span class="identifier">N</span><span class="special">)></span> <span class="special">\</span> |
| <span class="keyword">typename</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">::</span><span class="identifier">make_expr</span><span class="special"><</span> <span class="special">\</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">function</span> <span class="special">\</span> |
| <span class="special">,</span> <span class="identifier">lambda_domain</span> <span class="special">\</span> |
| <span class="special">,</span> <span class="identifier">construct_helper</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span> <span class="special">\</span> |
| <span class="special">,</span> <span class="identifier">A_const_ref</span><span class="special">(</span><span class="identifier">N</span><span class="special">)</span> <span class="special">\</span> |
| <span class="special">>::</span><span class="identifier">type</span> <span class="keyword">const</span> <span class="special">\</span> |
| <span class="identifier">construct</span><span class="special">(</span><span class="identifier">A_const_ref_a</span><span class="special">(</span><span class="identifier">N</span><span class="special">))</span> <span class="special">\</span> |
| <span class="special">{</span> <span class="special">\</span> |
| <span class="keyword">return</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">make_expr</span><span class="special"><</span> <span class="special">\</span> |
| <span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">function</span> <span class="special">\</span> |
| <span class="special">,</span> <span class="identifier">lambda_domain</span> <span class="special">\</span> |
| <span class="special">>(</span> <span class="special">\</span> |
| <span class="identifier">construct_helper</span><span class="special"><</span><span class="identifier">T</span><span class="special">>()</span> <span class="special">\</span> |
| <span class="special">,</span> <span class="identifier">ref_a</span><span class="special">(</span><span class="identifier">N</span><span class="special">)</span> <span class="special">\</span> |
| <span class="special">);</span> <span class="special">\</span> |
| <span class="special">}</span> |
| <span class="identifier">BOOST_PROTO_REPEAT_FROM_TO</span><span class="special">(</span><span class="number">1</span><span class="special">,</span> <span class="identifier">BOOST_PROTO_MAX_ARITY</span><span class="special">,</span> <span class="identifier">M0</span><span class="special">)</span> |
| <span class="preprocessor">#undef</span> <span class="identifier">M0</span> |
| |
| <span class="keyword">struct</span> <span class="identifier">S</span> |
| <span class="special">{</span> |
| <span class="identifier">S</span><span class="special">()</span> <span class="special">{}</span> |
| <span class="identifier">S</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">i</span><span class="special">,</span> <span class="keyword">char</span> <span class="identifier">c</span><span class="special">)</span> |
| <span class="special">{</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"S("</span> <span class="special"><<</span> <span class="identifier">i</span> <span class="special"><<</span> <span class="string">","</span> <span class="special"><<</span> <span class="identifier">c</span> <span class="special"><<</span> <span class="string">")\n"</span><span class="special">;</span> |
| <span class="special">}</span> |
| <span class="special">};</span> |
| |
| <span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> |
| <span class="special">{</span> |
| <span class="comment">// Create some lambda objects and immediately</span> |
| <span class="comment">// invoke them by applying their operator():</span> |
| <span class="keyword">int</span> <span class="identifier">i</span> <span class="special">=</span> <span class="special">(</span> <span class="special">(</span><span class="identifier">_1</span> <span class="special">+</span> <span class="number">2</span><span class="special">)</span> <span class="special">/</span> <span class="number">4</span> <span class="special">)(</span><span class="number">42</span><span class="special">);</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">i</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> <span class="comment">// prints 11</span> |
| |
| <span class="keyword">int</span> <span class="identifier">j</span> <span class="special">=</span> <span class="special">(</span> <span class="special">(-(</span><span class="identifier">_1</span> <span class="special">+</span> <span class="number">2</span><span class="special">))</span> <span class="special">/</span> <span class="number">4</span> <span class="special">)(</span><span class="number">42</span><span class="special">);</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">j</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> <span class="comment">// prints -11</span> |
| |
| <span class="keyword">double</span> <span class="identifier">d</span> <span class="special">=</span> <span class="special">(</span> <span class="special">(</span><span class="number">4</span> <span class="special">-</span> <span class="identifier">_2</span><span class="special">)</span> <span class="special">*</span> <span class="number">3</span> <span class="special">)(</span><span class="number">42</span><span class="special">,</span> <span class="number">3.14</span><span class="special">);</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">d</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> <span class="comment">// prints 2.58</span> |
| |
| <span class="comment">// check non-const ref terminals</span> |
| <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">_1</span> <span class="special"><<</span> <span class="string">" -- "</span> <span class="special"><<</span> <span class="identifier">_2</span> <span class="special"><<</span> <span class="char">'\n'</span><span class="special">)(</span><span class="number">42</span><span class="special">,</span> <span class="string">"Life, the Universe and Everything!"</span><span class="special">);</span> |
| <span class="comment">// prints "42 -- Life, the Universe and Everything!"</span> |
| |
| <span class="comment">// "Nullary" lambdas work too</span> |
| <span class="keyword">int</span> <span class="identifier">k</span> <span class="special">=</span> <span class="special">(</span><span class="identifier">val</span><span class="special">(</span><span class="number">1</span><span class="special">)</span> <span class="special">+</span> <span class="identifier">val</span><span class="special">(</span><span class="number">2</span><span class="special">))();</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">k</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> <span class="comment">// prints 3</span> |
| |
| <span class="comment">// check array indexing for kicks</span> |
| <span class="keyword">int</span> <span class="identifier">integers</span><span class="special">[</span><span class="number">5</span><span class="special">]</span> <span class="special">=</span> <span class="special">{</span><span class="number">0</span><span class="special">};</span> |
| <span class="special">(</span><span class="identifier">var</span><span class="special">(</span><span class="identifier">integers</span><span class="special">)[</span><span class="number">2</span><span class="special">]</span> <span class="special">=</span> <span class="number">2</span><span class="special">)();</span> |
| <span class="special">(</span><span class="identifier">var</span><span class="special">(</span><span class="identifier">integers</span><span class="special">)[</span><span class="identifier">_1</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">_1</span><span class="special">)(</span><span class="number">3</span><span class="special">);</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">integers</span><span class="special">[</span><span class="number">2</span><span class="special">]</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> <span class="comment">// prints 2</span> |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">integers</span><span class="special">[</span><span class="number">3</span><span class="special">]</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span> <span class="comment">// prints 3</span> |
| |
| <span class="comment">// Now use a lambda with an STL algorithm!</span> |
| <span class="keyword">int</span> <span class="identifier">rgi</span><span class="special">[</span><span class="number">4</span><span class="special">]</span> <span class="special">=</span> <span class="special">{</span><span class="number">1</span><span class="special">,</span><span class="number">2</span><span class="special">,</span><span class="number">3</span><span class="special">,</span><span class="number">4</span><span class="special">};</span> |
| <span class="keyword">char</span> <span class="identifier">rgc</span><span class="special">[</span><span class="number">4</span><span class="special">]</span> <span class="special">=</span> <span class="special">{</span><span class="char">'a'</span><span class="special">,</span><span class="char">'b'</span><span class="special">,</span><span class="char">'c'</span><span class="special">,</span><span class="char">'d'</span><span class="special">};</span> |
| <span class="identifier">S</span> <span class="identifier">rgs</span><span class="special">[</span><span class="number">4</span><span class="special">];</span> |
| |
| <span class="identifier">std</span><span class="special">::</span><span class="identifier">transform</span><span class="special">(</span><span class="identifier">rgi</span><span class="special">,</span> <span class="identifier">rgi</span><span class="special">+</span><span class="number">4</span><span class="special">,</span> <span class="identifier">rgc</span><span class="special">,</span> <span class="identifier">rgs</span><span class="special">,</span> <span class="identifier">construct</span><span class="special"><</span><span class="identifier">S</span><span class="special">>(</span><span class="identifier">_1</span><span class="special">,</span> <span class="identifier">_2</span><span class="special">));</span> |
| <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> |
| <span class="special">}</span> |
| </pre> |
| <p> |
| </p> |
| </div> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="boost_proto.users_guide.resources"></a><a class="link" href="users_guide.html#boost_proto.users_guide.resources" title="Background and Resources">Background and Resources</a> |
| </h3></div></div></div> |
| <p> |
| Proto was initially developed as part of <a href="../../../libs/xpressive/index.html" target="_top">Boost.Xpressive</a> |
| to simplify the job of transforming an expression template into an executable |
| finite state machine capable of matching a regular expression. Since then, |
| Proto has found application in the redesigned and improved Spirit-2 and the |
| related Karma library. As a result of these efforts, Proto evolved into a |
| generic and abstract grammar and tree transformation framework applicable |
| in a wide variety of DSEL scenarios. |
| </p> |
| <p> |
| The grammar and tree transformation framework is modeled on Spirit's grammar |
| and semantic action framework. The expression tree data structure is similar |
| to Fusion data structures in many respects, and is interoperable with Fusion's |
| iterators and algorithms. |
| </p> |
| <p> |
| The syntax for the grammar-matching features of <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><></span></code> is inspired by MPL's lambda expressions. |
| </p> |
| <p> |
| The idea for using function types for Proto's composite transforms is inspired |
| by Aleksey Gurtovoy's <a href="http://lists.boost.org/Archives/boost/2002/11/39718.php" target="_top">"round" |
| lambda</a> notation. |
| </p> |
| <a name="boost_proto.users_guide.resources.references"></a><h5> |
| <a name="boost_proto.users_guide.resources.references-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.resources.references">References</a> |
| </h5> |
| <div class="blockquote"><blockquote class="blockquote"><p> |
| <a name="boost_proto.users_guide.resources.SYB"></a>Ren, D. and Erwig, |
| M. 2006. A generic recursion toolbox for Haskell or: scrap your boilerplate |
| systematically. In <span class="emphasis"><em>Proceedings of the 2006 ACM SIGPLAN Workshop |
| on Haskell</em></span> (Portland, Oregon, USA, September 17 - 17, 2006). |
| Haskell '06. ACM, New York, NY, 13-24. DOI=<a href="http://doi.acm.org/10.1145/1159842.1159845" target="_top">http://doi.acm.org/10.1145/1159842.1159845</a> |
| </p></blockquote></div> |
| <a name="boost_proto.users_guide.resources.further_reading"></a><h5> |
| <a name="boost_proto.users_guide.resources.further_reading-heading"></a> |
| <a class="link" href="users_guide.html#boost_proto.users_guide.resources.further_reading">Further |
| Reading</a> |
| </h5> |
| <p> |
| A technical paper about an earlier version of Proto was accepted into the |
| <a href="http://lcsd.cs.tamu.edu/2007/" target="_top">ACM SIGPLAN Symposium on Library-Centric |
| Software Design LCSD'07</a>, and can be found at <a href="http://lcsd.cs.tamu.edu/2007/final/1/1_Paper.pdf" target="_top">http://lcsd.cs.tamu.edu/2007/final/1/1_Paper.pdf</a>. |
| The tree transforms described in that paper differ from what exists today. |
| </p> |
| </div> |
| <div class="section"> |
| <div class="titlepage"><div><div><h3 class="title"> |
| <a name="boost_proto.users_guide.glossary"></a><a class="link" href="users_guide.html#boost_proto.users_guide.glossary" title="Glossary">Glossary</a> |
| </h3></div></div></div> |
| <div class="variablelist"> |
| <p class="title"><b></b></p> |
| <dl> |
| <dt><span class="term"> <a name="boost_proto.users_guide.glossary.callable_transform"></a> callable transform</span></dt> |
| <dd><p> |
| A transform of the form <code class="computeroutput"><span class="identifier">R</span><span class="special">(</span><span class="identifier">A0</span><span class="special">,</span><span class="identifier">A1</span><span class="special">,...)</span></code> (i.e., a function type) where |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">is_callable</span><span class="special"><</span><span class="identifier">R</span><span class="special">>::</span><span class="identifier">value</span></code> is <code class="computeroutput"><span class="keyword">true</span></code>. |
| <code class="computeroutput"><span class="identifier">R</span></code> is treated as a polymorphic |
| function object and the arguments are treated as transforms that yield |
| the arguments to the function object. |
| </p></dd> |
| <dt><span class="term"> <a name="boost_proto.users_guide.glossary.context"></a> context</span></dt> |
| <dd><p> |
| In Proto, the term <span class="emphasis"><em>context</em></span> refers to an object |
| that can be passed, along with an expression to evaluate, to the <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">eval</span><span class="special">()</span></code> |
| function. The context determines how the expression is evaluated. All |
| context structs define a nested <code class="computeroutput"><span class="identifier">eval</span><span class="special"><></span></code> template that, when instantiated |
| with a node tag type (e.g., <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">plus</span></code>), |
| is a binary polymorphic function object that accepts an expression |
| of that type and the context object. In this way, contexts associate |
| behaviors with expression nodes. |
| </p></dd> |
| <dt><span class="term"> <a name="boost_proto.users_guide.glossary.domain"></a> domain</span></dt> |
| <dd><p> |
| In Proto, the term <span class="emphasis"><em>domain</em></span> refers to a type that |
| associates expressions within that domain with a <span class="emphasis"><em>generator</em></span> |
| for that domain and optionally a <span class="emphasis"><em>grammar</em></span> for the |
| domain. Domains are used primarily to imbue expressions within that |
| domain with additional members and to restrict Proto's operator overloads |
| such that expressions not conforming to the domain's grammar are never |
| created. Domains are empty structs that inherit from <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">domain</span><span class="special"><></span></code>. |
| </p></dd> |
| <dt><span class="term"> <a name="boost_proto.users_guide.glossary.dsel"></a> domain-specific embedded language</span></dt> |
| <dd><p> |
| A domain-specific language implemented as a library. The language in |
| which the library is written is called the "host" language, |
| and the language implemented by the library is called the "embedded" |
| language. |
| </p></dd> |
| <dt><span class="term"> <a name="boost_proto.users_guide.glossary.dsl"></a> domain-specific language</span></dt> |
| <dd><p> |
| A programming language that targets a particular problem space by providing |
| programming idioms, abstractions and constructs that match the constructs |
| within that problem space. |
| </p></dd> |
| <dt><span class="term"> <a name="boost_proto.users_guide.glossary.expression"></a> expression</span></dt> |
| <dd><p> |
| In Proto, an <span class="emphasis"><em>expression</em></span> is a heterogeneous tree |
| where each node is either an instantiation of <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">expr</span><span class="special"><></span></code>, <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">basic_expr</span><span class="special"><></span></code> or some type that is an extension |
| (via <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">extends</span><span class="special"><></span></code> |
| or <code class="computeroutput"><span class="identifier">BOOST_PROTO_EXTENDS</span><span class="special">()</span></code>) of such an instantiation. |
| </p></dd> |
| <dt><span class="term"> <a name="boost_proto.users_guide.glossary.expression_template"></a> expression template</span></dt> |
| <dd><p> |
| A C++ technique using templates and operator overloading to cause expressions |
| to build trees that represent the expression for lazy evaluation later, |
| rather than evaluating the expression eagerly. Some C++ libraries use |
| expression templates to build domain-specific embedded languages. |
| </p></dd> |
| <dt><span class="term"> <a name="boost_proto.users_guide.glossary.generator"></a> generator</span></dt> |
| <dd><p> |
| In Proto, a <span class="emphasis"><em>generator</em></span> is a unary polymorphic function |
| object that you specify when defining a <span class="emphasis"><em>domain</em></span>. |
| After constructing a new expression, Proto passes the expression to |
| your domain's generator for further processing. Often, the generator |
| wraps the expression in an extension wrapper that adds additional members |
| to it. |
| </p></dd> |
| <dt><span class="term"> <a name="boost_proto.users_guide.glossary.grammar"></a> grammar</span></dt> |
| <dd><p> |
| In Proto, a <span class="emphasis"><em>grammar</em></span> is a type that describes a |
| subset of Proto expression types. Expressions in a domain must conform |
| to that domain's grammar. The <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">matches</span><span class="special"><></span></code> metafunction evaluates whether |
| an expression type matches a grammar. Grammars are either primitives |
| such as <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span></code>, composites such as <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">plus</span><span class="special"><></span></code>, |
| control structures such as <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">or_</span><span class="special"><></span></code>, or some type derived from |
| a grammar. |
| </p></dd> |
| <dt><span class="term"> <a name="boost_proto.users_guide.glossary.object_transform"></a> object transform</span></dt> |
| <dd><p> |
| A transform of the form <code class="computeroutput"><span class="identifier">R</span><span class="special">(</span><span class="identifier">A0</span><span class="special">,</span><span class="identifier">A1</span><span class="special">,...)</span></code> (i.e., a function type) where |
| <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">is_callable</span><span class="special"><</span><span class="identifier">R</span><span class="special">>::</span><span class="identifier">value</span></code> is <code class="computeroutput"><span class="keyword">false</span></code>. |
| <code class="computeroutput"><span class="identifier">R</span></code> is treated as the |
| type of an object to construct and the arguments are treated as transforms |
| that yield the parameters to the constructor. |
| </p></dd> |
| <dt><span class="term"> <a name="boost_proto.users_guide.glossary.polymorphic_function_object"></a> polymorphic function object</span></dt> |
| <dd><p> |
| An instance of a class type with an overloaded function call operator |
| and a nested <code class="computeroutput"><span class="identifier">result_type</span></code> |
| typedef or <code class="computeroutput"><span class="identifier">result</span><span class="special"><></span></code> |
| template for calculating the return type of the function call operator. |
| </p></dd> |
| <dt><span class="term"> <a name="boost_proto.users_guide.glossary.primitive_transform"></a> primitive transform</span></dt> |
| <dd><p> |
| A type that defines a kind of polymorphic function object that takes |
| three arguments: expression, state, and data. Primitive transforms |
| can be used to compose callable transforms and object transforms. |
| </p></dd> |
| <dt><span class="term"> <a name="boost_proto.users_guide.glossary.transform"></a> transform</span></dt> |
| <dd><p> |
| Transforms are used to manipulate expression trees. They come in three |
| flavors: primitive transforms, callable transforms, or object transforms. |
| A transform <code class="computeroutput"><em class="replaceable"><code>T</code></em></code> can be made into |
| a ternary polymorphic function object with <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><></span></code>, as in <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">when</span><span class="special"><</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span><span class="special">,</span> <em class="replaceable"><code>T</code></em><span class="special">></span></code>. |
| Such a function object accepts <span class="emphasis"><em>expression</em></span>, <span class="emphasis"><em>state</em></span>, |
| and <span class="emphasis"><em>data</em></span> parameters, and computes a result from |
| them. |
| </p></dd> |
| </dl> |
| </div> |
| </div> |
| <div class="footnotes"> |
| <br><hr width="100" align="left"> |
| <div class="footnote"><p><sup>[<a id="ftn.id2338005" href="#id2338005" class="para">3</a>] </sup> |
| This error message was generated with Microsoft Visual C++ 9.0. Different |
| compilers will emit different messages with varying degrees of readability. |
| </p></div> |
| </div> |
| </div> |
| <table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> |
| <td align="left"></td> |
| <td align="right"><div class="copyright-footer">Copyright © 2008 Eric Niebler<p> |
| Distributed under the Boost Software License, Version 1.0. (See accompanying |
| file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>) |
| </p> |
| </div></td> |
| </tr></table> |
| <hr> |
| <div class="spirit-nav"> |
| <a accesskey="p" href="../proto.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../proto.html"><img src="../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="reference.html"><img src="../../../doc/src/images/next.png" alt="Next"></a> |
| </div> |
| </body> |
| </html> |