11061 lines
1.1 MiB
11061 lines
1.1 MiB
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||
<html>
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||
<title>Users' Guide</title>
|
||
<link rel="stylesheet" href="../../../doc/src/boostbook.css" type="text/css">
|
||
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
|
||
<link rel="home" href="../index.html" title="The Boost C++ Libraries BoostBook Documentation Subset">
|
||
<link rel="up" href="../proto.html" title="Chapter 33. Boost.Proto">
|
||
<link rel="prev" href="../proto.html" title="Chapter 33. 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 class="toc">
|
||
<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 EDSL</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>
|
||
<h4>
|
||
<a name="proto.users_guide.h0"></a>
|
||
<span class="phrase"><a name="proto.users_guide.compilers__compiler_construction_toolkits__and_proto"></a></span><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 an embedded domain-specific
|
||
language (EDSL). 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 EDSL.
|
||
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 class="variablelist">
|
||
<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 EDSL">Front Ends</a></span></dt>
|
||
<dd><p>
|
||
How to define the aspects of your EDSL 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 class="toc">
|
||
<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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.getting_started.installing_proto.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.getting_started.installing_proto.getting_proto"></a></span><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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.getting_started.installing_proto.h1"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.getting_started.installing_proto.building_with_proto"></a></span><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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.getting_started.installing_proto.h2"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.getting_started.installing_proto.requirements"></a></span><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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.getting_started.installing_proto.h3"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.getting_started.installing_proto.supported_compilers"></a></span><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" style="list-style-type: disc; ">
|
||
<li class="listitem">
|
||
Visual C++ 8 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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.getting_started.naming.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.getting_started.naming.functions"></a></span><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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.getting_started.naming.h1"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.getting_started.naming.metafunctions"></a></span><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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.getting_started.naming.h2"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.getting_started.naming.function_objects"></a></span><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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.getting_started.naming.h3"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.getting_started.naming.primitive_transforms"></a></span><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="boost_proto.users_guide.getting_started.naming.t0"></a><p class="title"><b>Table 33.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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.getting_started.hello_world.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.getting_started.hello_world.proto_design_philosophy"></a></span><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 EDSL (embedded domain-specific 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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.getting_started.hello_calculator.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.getting_started.hello_calculator.defining_terminals"></a></span><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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.getting_started.hello_calculator.h1"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.getting_started.hello_calculator.constructing_expression_trees"></a></span><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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.getting_started.hello_calculator.h2"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.getting_started.hello_calculator.evaluating_expression_trees"></a></span><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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.getting_started.hello_calculator.h3"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.getting_started.hello_calculator.customizing_expression_trees"></a></span><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 EDSL is already pretty useful, and for many EDSL 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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.getting_started.hello_calculator.h4"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.getting_started.hello_calculator.detecting_invalid_expressions"></a></span><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 EDSL 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 EDSL. 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 EDSL, 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 EDSL'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 EDSL short and readable compile-time errors when they accidentally
|
||
misuse your EDSL.
|
||
</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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.getting_started.hello_calculator.h5"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.getting_started.hello_calculator.controlling_operator_overloads"></a></span><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 EDSL'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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.getting_started.hello_calculator.h6"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.getting_started.hello_calculator.____and_much_more"></a></span><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 EDSL">Fronts Ends: Defining
|
||
Terminals and Non-Terminals of Your EDSL</a>
|
||
</h3></div></div></div>
|
||
<div class="toc"><dl class="toc">
|
||
<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.customizing_expressions_in_your_domain">Customizing
|
||
Expressions in Your Domain</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 an EDSL interface
|
||
using Proto. We'll cover the definition of terminals and lazy functions that
|
||
the users of your EDSL 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 an EDSL 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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.front_end.proto_s_operator_overloads.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.front_end.proto_s_operator_overloads.assignment__subscript__and_function_call_operators"></a></span><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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.front_end.proto_s_operator_overloads.h1"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.front_end.proto_s_operator_overloads.the_address_of_operator"></a></span><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 embedded domain-specific languages wouldn't be very expressive. Imagine
|
||
that we wanted to extend our calculator EDSL 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 EDSL 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>
|
||
I'm no expert at trigonometry, but that looks right to me.
|
||
</p>
|
||
<p>
|
||
We can write <code class="computeroutput"><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></code> because the <code class="computeroutput"><span class="identifier">sin</span></code>
|
||
object, which is a Proto terminal, has an overloaded <code class="computeroutput"><span class="keyword">operator</span><span class="special">()()</span></code> that builds a node representing a function
|
||
call invocation. The actual type of <code class="computeroutput"><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></code> is actually
|
||
something like this:
|
||
</p>
|
||
<pre class="programlisting"><span class="comment">// The type of the expression sin(pi/2):</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="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="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_child</span><span class="special"><</span> <span class="keyword">double</span> <span class="keyword">const</span> <span class="special">>::</span><span class="identifier">type</span>
|
||
<span class="special">>::</span><span class="identifier">type</span>
|
||
</pre>
|
||
<p>
|
||
This type further expands to an unsightly node type with a <span class="emphasis"><em>tag</em></span>
|
||
type of <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> and two children: the first
|
||
representing the function to be invoked, and the second representing the
|
||
argument to the function. (Node tag types describe the operation that created
|
||
the node. The difference between <code class="computeroutput"><span class="identifier">a</span>
|
||
<span class="special">+</span> <span class="identifier">b</span></code>
|
||
and <code class="computeroutput"><span class="identifier">a</span> <span class="special">-</span>
|
||
<span class="identifier">b</span></code> is that the former has tag
|
||
type <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 the latter has tag type <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>. Tag types are pure compile-time
|
||
information.)
|
||
</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>
|
||
In the type computation above, <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> is a metafunction that ensures
|
||
its argument is a Proto expression type. If it isn't one already, it
|
||
becomes a Proto terminal. We'll learn more about this metafunction, along
|
||
with <code class="computeroutput"><a class="link" href="../boost/proto/as_child.html" title="Function as_child">proto::as_child()</a></code>, its runtime counterpart,
|
||
<a class="link" href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child" title="Controlling How Child Expressions Are Captured">later</a>.
|
||
For now, you can forget about it.
|
||
</p></td></tr>
|
||
</table></div>
|
||
<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? Who knows?! You get to decide
|
||
when you define an evaluation context or a transform. But more on that
|
||
later.
|
||
</p>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.front_end.making_lazy_functions.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.front_end.making_lazy_functions.making_lazy_functions__continued"></a></span><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 EDSL 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++. (Well, technically it is; it means, <code class="computeroutput"><span class="identifier">pow</span></code>
|
||
less than 2, greater than <code class="computeroutput"><span class="special">(</span><span class="identifier">_1</span><span class="special">)</span></code>,
|
||
which is nothing at all like what we want.) <code class="computeroutput"><span class="identifier">pow</span></code>
|
||
should be a real function template. But it must be an unusual function:
|
||
one that returns an expression template.
|
||
</p>
|
||
<p>
|
||
With <code class="computeroutput"><span class="identifier">sin</span></code>, we relied on
|
||
Proto to provide an overloaded <code class="computeroutput"><span class="keyword">operator</span><span class="special">()()</span></code> to build an expression node with tag
|
||
type <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> for us. Now we'll need to do
|
||
so ourselves. As before, the node will have two children: the function
|
||
to invoke and the function's argument.
|
||
</p>
|
||
<p>
|
||
With <code class="computeroutput"><span class="identifier">sin</span></code>, the function
|
||
to invoke was a raw function pointer wrapped in a Proto terminal. In the
|
||
case of <code class="computeroutput"><span class="identifier">pow</span></code>, we want it
|
||
to be a terminal containing TR1-style function object. This will allow
|
||
us to parameterize the function on the exponent. Below is the implementation
|
||
of a simple TR1-style wrapper for the <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">pow</span></code>
|
||
function:
|
||
</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>
|
||
Following the <code class="computeroutput"><span class="identifier">sin</span></code> example,
|
||
we want <code class="computeroutput"><span class="identifier">pow</span><span class="special"><</span>
|
||
<span class="number">1</span> <span class="special">>(</span>
|
||
<span class="identifier">pi</span><span class="special">/</span><span class="number">2</span> <span class="special">)</span></code> to have
|
||
a type like this:
|
||
</p>
|
||
<pre class="programlisting"><span class="comment">// The type of the expression pow<1>(pi/2):</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">pow_fun</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="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="keyword">double</span> <span class="keyword">const</span> <span class="special">>::</span><span class="identifier">type</span>
|
||
<span class="special">>::</span><span class="identifier">type</span>
|
||
</pre>
|
||
<p>
|
||
We could write a <code class="computeroutput"><span class="identifier">pow</span><span class="special">()</span></code>
|
||
function using code like this, but it's verbose and error prone; it's too
|
||
easy to introduce subtle bugs by forgetting to call <code class="computeroutput"><a class="link" href="../boost/proto/as_child.html" title="Function as_child">proto::as_child()</a></code>
|
||
where necessary, resulting in code that seems to work but sometimes doesn't.
|
||
Proto provides a better way to construct expression nodes: <code class="computeroutput"><a class="link" href="../boost/proto/make_expr.html" title="Function make_expr">proto::make_expr()</a></code>.
|
||
</p>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.front_end.making_lazy_functions.h1"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.front_end.making_lazy_functions.lazy_functions_made_simple_with__literal_make_expr____literal_"></a></span><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>
|
||
Proto provides a helper for building expression templates called <code class="computeroutput"><a class="link" href="../boost/proto/make_expr.html" title="Function make_expr">proto::make_expr()</a></code>. We can concisely define
|
||
the <code class="computeroutput"><span class="identifier">pow</span><span class="special">()</span></code>
|
||
function with it as below.
|
||
</p>
|
||
<pre class="programlisting"><span class="comment">// Define a lazy pow() function for the calculator EDSL.</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>.
|
||
</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 child nodes. If a child
|
||
type is not already a Proto expression, it is automatically made into a
|
||
terminal with <code class="computeroutput"><a class="link" href="../boost/proto/as_child.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.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.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.
|
||
</p>
|
||
<p>
|
||
And that's it! <code class="computeroutput"><a class="link" href="../boost/proto/make_expr.html" title="Function make_expr">proto::make_expr()</a></code>
|
||
is the lazy person's way to make a lazy funtion.
|
||
</p>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain" title="Customizing Expressions in Your Domain">Customizing
|
||
Expressions in Your Domain</a>
|
||
</h4></div></div></div>
|
||
<div class="toc"><dl class="toc">
|
||
<dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.domains">Domains</a></span></dt>
|
||
<dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.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.customizing_expressions_in_your_domain.expression_generators">Expression
|
||
Generators</a></span></dt>
|
||
<dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.inhibiting_overloads">Controlling
|
||
Operator Overloads</a></span></dt>
|
||
<dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child">Controlling
|
||
How Child Expressions Are Captured</a></span></dt>
|
||
<dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.subdomains">EDSL
|
||
Interoperatability: Sub-Domains</a></span></dt>
|
||
</dl></div>
|
||
<p>
|
||
In this section, we'll learn all about <span class="emphasis"><em>domains</em></span>. In
|
||
particular, we'll learn:
|
||
</p>
|
||
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
|
||
<li class="listitem">
|
||
How to associate Proto expressions with a domain,
|
||
</li>
|
||
<li class="listitem">
|
||
How to add members to expressions within a domain,
|
||
</li>
|
||
<li class="listitem">
|
||
How to use a <span class="emphasis"><em>generator</em></span> to post-process all new
|
||
expressions created in your domain,
|
||
</li>
|
||
<li class="listitem">
|
||
How to control which operators are overloaded in a domain,
|
||
</li>
|
||
<li class="listitem">
|
||
How to specify capturing policies for child expressions and non-Proto
|
||
objects, and
|
||
</li>
|
||
<li class="listitem">
|
||
How to make expressions from separate domains interoperate.
|
||
</li>
|
||
</ul></div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h5 class="title">
|
||
<a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.domains"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.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 EDSL 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.customizing_expressions_in_your_domain.extends"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.extends.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.extends.retaining_pod_ness_with__literal_boost_proto_extends____literal_"></a></span><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.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__1_3_34_5_10_7.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__1_3_34_5_10_6.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="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.extends.t0"></a><p class="title"><b>Table 33.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__1_3_34_5_10_7.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__1_3_34_5_10_6.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__1_3_34_5_10_7.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__1_3_34_5_10_6.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.customizing_expressions_in_your_domain.expression_generators"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.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 EDSL 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.customizing_expressions_in_your_domain.inhibiting_overloads"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.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 an EDSL. 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 EDSL 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 class="section">
|
||
<div class="titlepage"><div><div><h5 class="title">
|
||
<a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child" title="Controlling How Child Expressions Are Captured">Controlling
|
||
How Child Expressions Are Captured</a>
|
||
</h5></div></div></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>
|
||
This is an advanced topic. Feel free to skip this if you're just getting
|
||
started with Proto.
|
||
</p></td></tr>
|
||
</table></div>
|
||
<p>
|
||
Proto's operator overloads build expressions from sub-expressions. The
|
||
sub-expressions become children of the new expression. By default, the
|
||
children are stored in the parent by reference. This section describes
|
||
how to change that default.
|
||
</p>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child.primer___literal_as_child__literal__vs___literal_as_expr__literal_"></a></span><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child.primer___literal_as_child__literal__vs___literal_as_expr__literal_">Primer:
|
||
<code class="literal">as_child</code> vs. <code class="literal">as_expr</code></a>
|
||
</h6>
|
||
<p>
|
||
Proto lets you independently customize the behavior of <code class="computeroutput"><a class="link" href="../boost/proto/as_child.html" title="Function as_child">proto::as_child()</a></code> and <code class="computeroutput"><a class="link" href="../boost/proto/as_expr.html" title="Function as_expr">proto::as_expr()</a></code>.
|
||
Both accept an object <code class="literal">x</code> and return a Proto expression
|
||
by turning <code class="literal">x</code> it into a Proto terminal if necessary.
|
||
Although similar, the two functions are used in different situations
|
||
and have subtly different behavior by default. It's important to understand
|
||
the difference so that you know which to customize to achieve the behavior
|
||
you want.
|
||
</p>
|
||
<p>
|
||
To wit: <code class="computeroutput"><a class="link" href="../boost/proto/as_expr.html" title="Function as_expr">proto::as_expr()</a></code> is typically used by
|
||
<span class="emphasis"><em>you</em></span> to turn an object into a Proto expression that
|
||
is to be held in a local variable, as so:
|
||
</p>
|
||
<pre class="programlisting"><span class="keyword">auto</span> <span class="identifier">l</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">x</span><span class="special">);</span> <span class="comment">// Turn x into a Proto expression, hold the result in a local</span>
|
||
</pre>
|
||
<p>
|
||
The above works regardless of whether <code class="computeroutput"><span class="identifier">x</span></code>
|
||
is already a Proto expression or not. The object <code class="computeroutput"><span class="identifier">l</span></code>
|
||
is guaranteed to be a valid Proto expression. If <code class="computeroutput"><span class="identifier">x</span></code>
|
||
is a non-Proto object, it is turned into a terminal expression that holds
|
||
<code class="computeroutput"><span class="identifier">x</span></code> <span class="emphasis"><em>by value</em></span>.<a href="#ftn.boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child.f0" class="footnote" name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child.f0"><sup class="footnote">[34]</sup></a> If <code class="computeroutput"><span class="identifier">x</span></code> is a
|
||
Proto object already, <code class="computeroutput"><a class="link" href="../boost/proto/as_expr.html" title="Function as_expr">proto::as_expr()</a></code>
|
||
returns it <span class="emphasis"><em>by value</em></span> unmodified.
|
||
</p>
|
||
<p>
|
||
In contrast, <code class="computeroutput"><a class="link" href="../boost/proto/as_child.html" title="Function as_child">proto::as_child()</a></code>
|
||
is used internally by Proto to pre-process objects before making them
|
||
children of another expression. Since it's internal to Proto, you don't
|
||
see it explicitly, but it's there behind the scenes in expressions like
|
||
this:
|
||
</p>
|
||
<pre class="programlisting"><span class="identifier">x</span> <span class="special">+</span> <span class="identifier">y</span><span class="special">;</span> <span class="comment">// Consider that y is a Proto expression, but x may or may not be.</span>
|
||
</pre>
|
||
<p>
|
||
In this case, Proto builds a plus node from the two children. Both are
|
||
pre-processed by passing them to <code class="computeroutput"><a class="link" href="../boost/proto/as_child.html" title="Function as_child">proto::as_child()</a></code>
|
||
before making them children of the new node. If <code class="computeroutput"><span class="identifier">x</span></code>
|
||
is not a Proto expression, it becomes one by being wrapped in a Proto
|
||
terminal that holds it <span class="emphasis"><em>by reference</em></span>. If <code class="computeroutput"><span class="identifier">x</span></code> is already a Proto expression, <code class="computeroutput"><a class="link" href="../boost/proto/as_child.html" title="Function as_child">proto::as_child()</a></code> returns it <span class="emphasis"><em>by
|
||
reference</em></span> unmodified. Contrast this with the above description
|
||
for <code class="computeroutput"><a class="link" href="../boost/proto/as_expr.html" title="Function as_expr">proto::as_expr()</a></code>.
|
||
</p>
|
||
<p>
|
||
The table below summarizes the above description.
|
||
</p>
|
||
<div class="table">
|
||
<a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child.t0"></a><p class="title"><b>Table 33.3. proto::as_expr() vs. proto::as_child()</b></p>
|
||
<div class="table-contents"><table class="table" summary="proto::as_expr() vs. proto::as_child()">
|
||
<colgroup>
|
||
<col>
|
||
<col>
|
||
<col>
|
||
</colgroup>
|
||
<thead><tr>
|
||
<th>
|
||
<p>
|
||
<span class="bold"><strong>Function</strong></span>
|
||
</p>
|
||
</th>
|
||
<th>
|
||
<p>
|
||
<span class="bold"><strong>When <code class="literal">t</code> is not a Proto
|
||
expr...</strong></span>
|
||
</p>
|
||
</th>
|
||
<th>
|
||
<p>
|
||
<span class="bold"><strong>When <code class="literal">t</code> is a Proto
|
||
expr...</strong></span>
|
||
</p>
|
||
</th>
|
||
</tr></thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>
|
||
<p>
|
||
<code class="literal">proto::as_expr(t)</code>
|
||
</p>
|
||
</td>
|
||
<td>
|
||
<p>
|
||
Return (by value) a new Proto terminal holding <code class="literal">t</code>
|
||
by value.
|
||
</p>
|
||
</td>
|
||
<td>
|
||
<p>
|
||
Return <code class="literal">t</code> by value unmodified.
|
||
</p>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>
|
||
<p>
|
||
<code class="literal">proto::as_child(t)</code>
|
||
</p>
|
||
</td>
|
||
<td>
|
||
<p>
|
||
Return (by value) a new Proto terminal holding <code class="literal">t</code>
|
||
by reference.
|
||
</p>
|
||
</td>
|
||
<td>
|
||
<p>
|
||
Return <code class="literal">t</code> by reference unmodified.
|
||
</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>
|
||
There is one important place where Proto uses both <code class="computeroutput"><span class="identifier">as_expr</span></code>
|
||
<span class="emphasis"><em>and</em></span> <code class="computeroutput"><span class="identifier">as_child</span></code>:
|
||
<code class="computeroutput"><a class="link" href="../boost/proto/make_expr.html" title="Function make_expr">proto::make_expr()</a></code>. The <code class="computeroutput"><a class="link" href="../boost/proto/make_expr.html" title="Function make_expr">proto::make_expr()</a></code> function requires
|
||
you to specify for each child whether it should be held by value or
|
||
by reference. Proto uses <code class="computeroutput"><a class="link" href="../boost/proto/as_expr.html" title="Function as_expr">proto::as_expr()</a></code>
|
||
to pre-process the children to be held by value, and <code class="computeroutput"><a class="link" href="../boost/proto/as_child.html" title="Function as_child">proto::as_child()</a></code> for the ones to be
|
||
held by reference.
|
||
</p></td></tr>
|
||
</table></div>
|
||
<p>
|
||
Now that you know what <code class="computeroutput"><a class="link" href="../boost/proto/as_child.html" title="Function as_child">proto::as_child()</a></code>
|
||
and <code class="computeroutput"><a class="link" href="../boost/proto/as_expr.html" title="Function as_expr">proto::as_expr()</a></code> are, where they are
|
||
used, and what they do by default, you may decide that one or both of
|
||
these functions should have different behavior for your domain. For instance,
|
||
given the above description of <code class="computeroutput"><a class="link" href="../boost/proto/as_child.html" title="Function as_child">proto::as_child()</a></code>,
|
||
the following code is always wrong:
|
||
</p>
|
||
<pre class="programlisting"><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="keyword">auto</span> <span class="identifier">l</span> <span class="special">=</span> <span class="identifier">i</span> <span class="special">+</span> <span class="number">42</span><span class="special">;</span> <span class="comment">// This is WRONG! Don't do this.</span>
|
||
</pre>
|
||
<p>
|
||
Why is this wrong? Because <code class="computeroutput"><a class="link" href="../boost/proto/as_child.html" title="Function as_child">proto::as_child()</a></code>
|
||
will turn the integer literal 42 into a Proto terminal that holds a reference
|
||
to a temporary integer initialized with 42. The lifetime of that temporary
|
||
ends at the semicolon, guaranteeing that the local <code class="computeroutput"><span class="identifier">l</span></code>
|
||
is left holding a dangling reference to a deceased integer. What to do?
|
||
One answer is to use <code class="computeroutput"><a class="link" href="../boost/proto/deep_copy.html" title="Function template deep_copy">proto::deep_copy()</a></code>.
|
||
Another is to customize the behavior of <code class="computeroutput"><a class="link" href="../boost/proto/as_child.html" title="Function as_child">proto::as_child()</a></code>
|
||
for your domain. Read on for the details.
|
||
</p>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child.h1"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child.per_domain__literal_as_child__literal_"></a></span><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child.per_domain__literal_as_child__literal_">Per-Domain
|
||
<code class="literal">as_child</code></a>
|
||
</h6>
|
||
<p>
|
||
To control how Proto builds expressions out of sub-expressions in your
|
||
domain, define your domain as usual, and then define a nested <code class="computeroutput"><span class="identifier">as_child</span><span class="special"><></span></code>
|
||
class template within it, as follows:
|
||
</p>
|
||
<pre class="programlisting"><span class="keyword">class</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">my_generator</span><span class="special">,</span> <span class="identifier">my_grammar</span> <span class="special">></span>
|
||
<span class="special">{</span>
|
||
<span class="comment">// Here is where you define how Proto should handle</span>
|
||
<span class="comment">// sub-expressions that are about to be glommed into</span>
|
||
<span class="comment">// a larger 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">struct</span> <span class="identifier">as_child</span>
|
||
<span class="special">{</span>
|
||
<span class="keyword">typedef</span> <span class="emphasis"><em><code class="literal">unspecified-Proto-expr-type</code></em></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">T</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="keyword">return</span> <span class="emphasis"><em><code class="literal">unspecified-Proto-expr-object</code></em></span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="special">};</span>
|
||
<span class="special">};</span>
|
||
</pre>
|
||
<p>
|
||
There's one important thing to note: in the above code, the template
|
||
parameter <code class="literal">T</code> may or may not be a Proto expression type,
|
||
but the result <span class="emphasis"><em>must</em></span> be a Proto expression type,
|
||
or a reference to one. That means that most user-defined <code class="literal">as_child<></code>
|
||
templates will need to check whether <code class="literal">T</code> is an expression
|
||
or not (using <code class="computeroutput"><a class="link" href="../boost/proto/is_expr.html" title="Struct template is_expr">proto::is_expr<></a></code>), and then turn non-expressions
|
||
into Proto terminals by wrapping them as <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">terminal</span><span class="special"><</span> <span class="comment">/* ... */</span>
|
||
<span class="special">>::</span><span class="identifier">type</span></code>
|
||
or equivalent.
|
||
</p>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child.h2"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child.per_domain__literal_as_expr__literal_"></a></span><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child.per_domain__literal_as_expr__literal_">Per-Domain
|
||
<code class="literal">as_expr</code></a>
|
||
</h6>
|
||
<p>
|
||
Although less common, Proto also lets you customize the behavior of
|
||
<code class="computeroutput"><a class="link" href="../boost/proto/as_expr.html" title="Function as_expr">proto::as_expr()</a></code> on a per-domain basis.
|
||
The technique is identical to that for <code class="literal">as_child</code>. See
|
||
below:
|
||
</p>
|
||
<pre class="programlisting"><span class="keyword">class</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">my_generator</span><span class="special">,</span> <span class="identifier">my_grammar</span> <span class="special">></span>
|
||
<span class="special">{</span>
|
||
<span class="comment">// Here is where you define how Proto should handle</span>
|
||
<span class="comment">// objects that are to be turned into expressions</span>
|
||
<span class="comment">// fit for storage in local variables.</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">as_expr</span>
|
||
<span class="special">{</span>
|
||
<span class="keyword">typedef</span> <span class="emphasis"><em><code class="literal">unspecified-Proto-expr-type</code></em></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">T</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="keyword">return</span> <span class="emphasis"><em><code class="literal">unspecified-Proto-expr-object</code></em></span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="special">};</span>
|
||
<span class="special">};</span>
|
||
</pre>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child.h3"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child.making_proto_expressions__literal_auto__literal__safe"></a></span><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child.making_proto_expressions__literal_auto__literal__safe">Making
|
||
Proto Expressions <code class="literal">auto</code>-safe</a>
|
||
</h6>
|
||
<p>
|
||
Let's look again at the problem described above involving the C++11
|
||
<code class="computeroutput"><span class="keyword">auto</span></code> keyword and the default
|
||
behavior of <code class="computeroutput"><a class="link" href="../boost/proto/as_child.html" title="Function as_child">proto::as_child()</a></code>.
|
||
</p>
|
||
<pre class="programlisting"><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="keyword">auto</span> <span class="identifier">l</span> <span class="special">=</span> <span class="identifier">i</span> <span class="special">+</span> <span class="number">42</span><span class="special">;</span> <span class="comment">// This is WRONG! Don't do this.</span>
|
||
</pre>
|
||
<p>
|
||
Recall that the problem is the lifetime of the temporary integer created
|
||
to hold the value 42. The local <code class="computeroutput"><span class="identifier">l</span></code>
|
||
will be left holding a dangling reference to it after its lifetime is
|
||
over. What if we want Proto to make expressions safe to store this way
|
||
in local variables? We can do so very easily by making <code class="computeroutput"><a class="link" href="../boost/proto/as_child.html" title="Function as_child">proto::as_child()</a></code> behave just like <code class="computeroutput"><a class="link" href="../boost/proto/as_expr.html" title="Function as_expr">proto::as_expr()</a></code>. The following code
|
||
achieves this:
|
||
</p>
|
||
<pre class="programlisting"><span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">E</span> <span class="special">></span>
|
||
<span class="keyword">struct</span> <span class="identifier">my_expr</span><span class="special">;</span>
|
||
|
||
<span class="keyword">struct</span> <span class="identifier">my_generator</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">my_expr</span> <span class="special">></span>
|
||
<span class="special">{};</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">my_generator</span> <span class="special">></span>
|
||
<span class="special">{</span>
|
||
<span class="comment">// Make as_child() behave like as_expr() in my_domain.</span>
|
||
<span class="comment">// (proto_base_domain is a typedef for proto::domain< my_generator ></span>
|
||
<span class="comment">// that is defined in proto::domain<>.)</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">as_child</span>
|
||
<span class="special">:</span> <span class="identifier">proto_base_domain</span><span class="special">::</span><span class="identifier">as_expr</span><span class="special"><</span> <span class="identifier">T</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">E</span> <span class="special">></span>
|
||
<span class="keyword">struct</span> <span class="identifier">my_expr</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">BOOST_PROTO_EXTENDS</span><span class="special">(</span> <span class="identifier">E</span><span class="special">,</span> <span class="identifier">my_expr</span><span class="special"><</span> <span class="identifier">E</span> <span class="special">>,</span> <span class="identifier">my_domain</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">literal</span><span class="special"><</span> <span class="keyword">int</span><span class="special">,</span> <span class="identifier">my_domain</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="keyword">auto</span> <span class="identifier">l</span> <span class="special">=</span> <span class="identifier">i</span> <span class="special">+</span> <span class="number">42</span><span class="special">;</span> <span class="comment">// OK! Everything is stored by value here.</span>
|
||
</pre>
|
||
<p>
|
||
Notice that <code class="computeroutput"><span class="identifier">my_domain</span><span class="special">::</span><span class="identifier">as_child</span><span class="special"><></span></code> simply defers to the default
|
||
implementation of <code class="computeroutput"><span class="identifier">as_expr</span><span class="special"><></span></code> found in <code class="computeroutput"><a class="link" href="../boost/proto/domain.html" title="Struct template domain">proto::domain<></a></code>.
|
||
By simply cross-wiring our domain's <code class="computeroutput"><span class="identifier">as_child</span><span class="special"><></span></code> to <code class="computeroutput"><span class="identifier">as_expr</span><span class="special"><></span></code>, we guarantee that all terminals
|
||
that can be held by value are, and that all child expressions are also
|
||
held by value. This increases copying and may incur a runtime performance
|
||
cost, but it eliminates any spector of lifetime management issues.
|
||
</p>
|
||
<p>
|
||
For another example, see the definition of <code class="computeroutput"><span class="identifier">lldomain</span></code>
|
||
in <code class="literal">libs/proto/example/lambda.hpp</code>. That example is
|
||
a complete reimplementation of the Boost Lambda Library (BLL) on top
|
||
of Boost.Proto. The function objects the BLL generates are safe to be
|
||
stored in local variables. To emulate this with Proto, the <code class="computeroutput"><span class="identifier">lldomain</span></code> cross-wires <code class="computeroutput"><span class="identifier">as_child</span><span class="special"><></span></code>
|
||
to <code class="computeroutput"><span class="identifier">as_expr</span><span class="special"><></span></code>
|
||
as above, but with one extra twist: objects with array type are also
|
||
stored by reference. Check it out.
|
||
</p>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h5 class="title">
|
||
<a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.subdomains"></a><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.subdomains" title="EDSL Interoperatability: Sub-Domains">EDSL
|
||
Interoperatability: Sub-Domains</a>
|
||
</h5></div></div></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>
|
||
This is an advanced topic. Feel free to skip this if you're just getting
|
||
started with Proto.
|
||
</p></td></tr>
|
||
</table></div>
|
||
<p>
|
||
The ability to <span class="emphasis"><em>compose</em></span> different EDSLs is one of
|
||
their most exciting features. Consider how you build a parser using yacc.
|
||
You write your grammar rules in yacc's domain-specific language. Then
|
||
you embed semantic actions written in C within your grammar. Boost's
|
||
Spirit parser generator gives you the same ability. You write grammar
|
||
rules using Spirit.Qi and embed semantic actions using the Phoenix library.
|
||
Phoenix and Spirit are both Proto-based domain-specific languages with
|
||
their own distinct syntax and semantics. But you can freely embed Phoenix
|
||
expressions within Spirit expressions. This section describes Proto's
|
||
<span class="emphasis"><em>sub-domain</em></span> feature that lets you define families
|
||
of interoperable domains.
|
||
</p>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.subdomains.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.subdomains.dueling_domains"></a></span><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.subdomains.dueling_domains">Dueling
|
||
Domains</a>
|
||
</h6>
|
||
<p>
|
||
When you try to create an expression from two sub-expressions in different
|
||
domains, what is the domain of the resulting expression? This is the
|
||
fundamental problem that is addressed by sub-domains. Consider the following
|
||
code:
|
||
</p>
|
||
<pre class="programlisting"><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="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="comment">// Forward-declare two expression wrappers</span>
|
||
<span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">E</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">spirit_expr</span><span class="special">;</span>
|
||
<span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">E</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">phoenix_expr</span><span class="special">;</span>
|
||
|
||
<span class="comment">// Define two domains</span>
|
||
<span class="keyword">struct</span> <span class="identifier">spirit_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">spirit_expr</span><span class="special">></span> <span class="special">></span> <span class="special">{};</span>
|
||
<span class="keyword">struct</span> <span class="identifier">phoenix_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">phoenix_expr</span><span class="special">></span> <span class="special">></span> <span class="special">{};</span>
|
||
|
||
<span class="comment">// Implement the two expression wrappers</span>
|
||
<span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">E</span><span class="special">></span>
|
||
<span class="keyword">struct</span> <span class="identifier">spirit_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">spirit_expr</span><span class="special"><</span><span class="identifier">E</span><span class="special">>,</span> <span class="identifier">spirit_domain</span><span class="special">></span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">spirit_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="identifier">E</span><span class="special">())</span> <span class="special">:</span> <span class="identifier">spirit_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="special">};</span>
|
||
|
||
<span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">E</span><span class="special">></span>
|
||
<span class="keyword">struct</span> <span class="identifier">phoenix_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">phoenix_expr</span><span class="special"><</span><span class="identifier">E</span><span class="special">>,</span> <span class="identifier">phoenix_domain</span><span class="special">></span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">phoenix_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="identifier">E</span><span class="special">())</span> <span class="special">:</span> <span class="identifier">phoenix_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="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">spirit_domain</span><span class="special">></span> <span class="identifier">sp</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">literal</span><span class="special"><</span><span class="keyword">int</span><span class="special">,</span> <span class="identifier">phoenix_domain</span><span class="special">></span> <span class="identifier">phx</span><span class="special">(</span><span class="number">0</span><span class="special">);</span>
|
||
|
||
<span class="comment">// Whoops! What does it mean to add two expressions in different domains?</span>
|
||
<span class="identifier">sp</span> <span class="special">+</span> <span class="identifier">phx</span><span class="special">;</span> <span class="comment">// ERROR</span>
|
||
<span class="special">}</span>
|
||
</pre>
|
||
<p>
|
||
Above, we define two domains called <code class="computeroutput"><span class="identifier">spirit_domain</span></code>
|
||
and <code class="computeroutput"><span class="identifier">phoenix_domain</span></code> and
|
||
declare two int literals in each. Then we try to compose them into a
|
||
larger expression using Proto's binary plus operator, and it fails. Proto
|
||
can't figure out whether the resulting expression should be in the Spirit
|
||
domain or the Phoenix domain, and thus whether it should be an instance
|
||
of <code class="computeroutput"><span class="identifier">spirit_expr</span><span class="special"><></span></code>
|
||
or <code class="computeroutput"><span class="identifier">phoenix_expr</span><span class="special"><></span></code>.
|
||
We have to tell Proto how to resolve the conflict. We can do that by
|
||
declaring that Phoenix is a sub-domain of Spirit as in the following
|
||
definition of <code class="computeroutput"><span class="identifier">phoenix_domain</span></code>:
|
||
</p>
|
||
<pre class="programlisting"><span class="comment">// Declare that phoenix_domain is a sub-domain of spirit_domain</span>
|
||
<span class="keyword">struct</span> <span class="identifier">phoenix_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">phoenix_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="bold"><strong>spirit_domain</strong></span><span class="special">></span>
|
||
<span class="special">{};</span>
|
||
</pre>
|
||
<p>
|
||
The third template parameter to <code class="computeroutput"><a class="link" href="../boost/proto/domain.html" title="Struct template domain">proto::domain<></a></code>
|
||
is the super-domain. By defining <code class="computeroutput"><span class="identifier">phoenix_domain</span></code>
|
||
as above, we are saying that Phoenix expressions can be combined with
|
||
Spirit expressions, and that when that happens, the resulting expression
|
||
should be a Spirit expression.
|
||
</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>
|
||
If you are wondering what the purpose of <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span></code>
|
||
is in the definition of <code class="computeroutput"><span class="identifier">phoenix_domain</span></code>
|
||
above, recall that the second template parameter to <code class="computeroutput"><a class="link" href="../boost/proto/domain.html" title="Struct template domain">proto::domain<></a></code>
|
||
is the domain's grammar. <span class="quote">“<span class="quote"><code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_</span></code></span>”</span>
|
||
is the default and signifies that the domain places no restrictions
|
||
on the expressions that are valid within it.
|
||
</p></td></tr>
|
||
</table></div>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.subdomains.h1"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.subdomains.domain_resolution"></a></span><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.subdomains.domain_resolution">Domain
|
||
Resolution</a>
|
||
</h6>
|
||
<p>
|
||
When there are multiple domains in play within a given expression, Proto
|
||
uses some rules to figure out which domain "wins". The rules
|
||
are loosely modeled on the rules for C++ inheritance. <code class="computeroutput"><span class="identifier">Phoenix_domain</span></code>
|
||
is a sub-domain of <code class="computeroutput"><span class="identifier">spirit_domain</span></code>.
|
||
You can liken that to a derived/base relationship that gives Phoenix
|
||
expressions a kind of implicit conversion to Spirit expressions. And
|
||
since Phoenix expressions can be "converted" to Spirit expressions,
|
||
they can be freely combined with Spirit expressions and the result is
|
||
a Spirit expression.
|
||
</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>
|
||
Super- and sub-domains are not actually implemented using inheritance.
|
||
This is only a helpful mental model.
|
||
</p></td></tr>
|
||
</table></div>
|
||
<p>
|
||
The analogy with inheritance holds even in the case of three domains
|
||
when two are sub-domains of the third. Imagine another domain called
|
||
<code class="computeroutput"><span class="identifier">foobar_domain</span></code> that was
|
||
also a sub-domain of <code class="computeroutput"><span class="identifier">spirit_domain</span></code>.
|
||
Expressions in the <code class="computeroutput"><span class="identifier">foobar_domain</span></code>
|
||
could be combined with expressions in the <code class="computeroutput"><span class="identifier">phoenix_domain</span></code>
|
||
and the resulting expression would be in the <code class="computeroutput"><span class="identifier">spirit_domain</span></code>.
|
||
That's because expressions in the two sub-domains both have "conversions"
|
||
to the super-domain, so the operation is allowed and the super-domain
|
||
wins.
|
||
</p>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.subdomains.h2"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.subdomains.the_default_domain"></a></span><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.subdomains.the_default_domain">The
|
||
Default Domain</a>
|
||
</h6>
|
||
<p>
|
||
When you don't assign a Proto expression to a particular domain, Proto
|
||
considers it a member of the so-called default domain, <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">default_domain</span></code>. Even non-Proto objects
|
||
are treated as terminals in the default domain. Consider:
|
||
</p>
|
||
<pre class="programlisting"><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">spirit_domain</span><span class="special">></span> <span class="identifier">sp</span><span class="special">(</span><span class="number">0</span><span class="special">);</span>
|
||
|
||
<span class="comment">// Add 1 to a spirit expression. Result is a spirit expression.</span>
|
||
<span class="identifier">sp</span> <span class="special">+</span> <span class="number">1</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
</pre>
|
||
<p>
|
||
Expressions in the default domain (or non-expressions like <code class="literal">1</code>)
|
||
have a kind of implicit conversion to expressions every other domain
|
||
type. What's more, you can define your domain to be a sub-domain of the
|
||
default domain. In so doing, you give expressions in your domain conversions
|
||
to expressions in every other domain. This is like a <span class="quote">“<span class="quote">free love</span>”</span>
|
||
domain, because it will freely mix with all other domains.
|
||
</p>
|
||
<p>
|
||
Let's think again about the Phoenix EDSL. Since it provides generally
|
||
useful lambda functionality, it's reasonable to assume that lots of other
|
||
EDSLs besides Spirit might want the ability to embed Phoenix expressions.
|
||
In other words, <code class="computeroutput"><span class="identifier">phoenix_domain</span></code>
|
||
should be a sub-domain of <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">default_domain</span></code>,
|
||
not <code class="computeroutput"><span class="identifier">spirit_domain</span></code>:
|
||
</p>
|
||
<pre class="programlisting"><span class="comment">// Declare that phoenix_domain is a sub-domain of proto::default_domain</span>
|
||
<span class="keyword">struct</span> <span class="identifier">phoenix_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">phoenix_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">default_domain</span><span class="special">></span>
|
||
<span class="special">{};</span>
|
||
</pre>
|
||
<p>
|
||
That's much better. Phoenix expressions can now be put anywhere.
|
||
</p>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.subdomains.h3"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.subdomains.sub_domain_summary"></a></span><a class="link" href="users_guide.html#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.subdomains.sub_domain_summary">Sub-Domain
|
||
Summary</a>
|
||
</h6>
|
||
<p>
|
||
Use Proto sub-domains to make it possible to mix expressions from multiple
|
||
domains. And when you want expressions in your domain to freely combine
|
||
with <span class="emphasis"><em>all</em></span> expressions, make it a sub-domain of <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">default_domain</span></code>.
|
||
</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__1_3_34_5_33_3.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__1_3_34_5_33_3.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__1_3_34_5_33_3.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__1_3_34_5_33_3.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 an EDSL 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 EDSL, 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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.front_end.code_repetition.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.front_end.code_repetition.non_default_sequences"></a></span><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__1_3_34_5_37_5.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__1_3_34_5_37_5.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 class="toc">
|
||
<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 EDSL "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>
|
||
<h5>
|
||
<a name="boost_proto.users_guide.intermediate_form.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.intermediate_form.the__literal_expr_lt__gt___literal__type"></a></span><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>
|
||
<h5>
|
||
<a name="boost_proto.users_guide.intermediate_form.h1"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.intermediate_form.building_expression_trees"></a></span><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" style="list-style-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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.intermediate_form.left_right_child.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.intermediate_form.left_right_child.getting_expression_tags_and_arities"></a></span><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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.intermediate_form.left_right_child.h1"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.intermediate_form.left_right_child.getting_terminal_values"></a></span><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.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.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="boost_proto.users_guide.intermediate_form.left_right_child.t0"></a><p class="title"><b>Table 33.4. 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> <a href="#ftn.boost_proto.users_guide.intermediate_form.left_right_child.f0" class="footnote" name="boost_proto.users_guide.intermediate_form.left_right_child.f0"><sup class="footnote">[a]</sup></a></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 id="ftn.boost_proto.users_guide.intermediate_form.left_right_child.f0" class="footnote"><p><a href="#boost_proto.users_guide.intermediate_form.left_right_child.f0" class="para"><sup class="para">[a] </sup></a>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"><h6>
|
||
<a name="boost_proto.users_guide.intermediate_form.left_right_child.h2"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.intermediate_form.left_right_child.getting_child_expressions"></a></span><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.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="boost_proto.users_guide.intermediate_form.left_right_child.t1"></a><p class="title"><b>Table 33.5. 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"><h6>
|
||
<a name="boost_proto.users_guide.intermediate_form.left_right_child.h3"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.intermediate_form.left_right_child.common_shortcuts"></a></span><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.html" title="Function child">proto::child()</a></code>,
|
||
<code class="computeroutput"><a class="link" href="../boost/proto/left.html" title="Function left">proto::left()</a></code>, and <code class="computeroutput"><a class="link" href="../boost/proto/right.html" title="Function right">proto::right()</a></code>
|
||
functions. <code class="computeroutput"><a class="link" href="../boost/proto/child.html" title="Function child">proto::child()</a></code> and <code class="computeroutput"><a class="link" href="../boost/proto/left.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.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 EDSL 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="keyword">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.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.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 EDSL. It's called <code class="computeroutput"><a class="link" href="../boost/proto/display_expr.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.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="boost_proto.users_guide.intermediate_form.tags_and_metafunctions.t0"></a><p class="title"><b>Table 33.6. 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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.intermediate_form.expressions_as_fusion_sequences.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.intermediate_form.expressions_as_fusion_sequences.flattening_proto_expression_tress"></a></span><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.html" title="Function flatten">proto::flatten()</a></code>
|
||
function. <code class="computeroutput"><a class="link" href="../boost/proto/flatten.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 class="toc">
|
||
<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_edsl_grammars">Defining
|
||
EDSL 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 EDSL 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="boost_proto.users_guide.intermediate_form.expression_introspection.fuzzy_and_exact_matches_of_terminals.t0"></a><p class="title"><b>Table 33.7. 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 EDSL 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 EDSL. 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_edsl_grammars"></a><a class="link" href="users_guide.html#boost_proto.users_guide.intermediate_form.expression_introspection.defining_edsl_grammars" title="Defining EDSL Grammars">Defining
|
||
EDSL Grammars</a>
|
||
</h5></div></div></div>
|
||
<p>
|
||
In this section we'll see how to use Proto to define a grammar for your
|
||
EDSL 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 EDSL 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 EDSL. This is easy to express with a grammar,
|
||
and hard to do with straight operator overloading.
|
||
</p>
|
||
<p>
|
||
Third, using an EDSL 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 an EDSL 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 EDSL 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 EDSL 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 class="toc">
|
||
<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 EDSL 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" style="list-style-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.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.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 class="toc">
|
||
<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.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.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.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.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.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.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.html" title="Function eval">proto::eval()</a></code>. The following demonstrates
|
||
a use of <code class="computeroutput"><a class="link" href="../boost/proto/eval.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.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.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.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.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.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 class="variablelist">
|
||
<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="keyword">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="keyword">decltype</span></code>
|
||
to calculate the return type of the function call operator. <code class="computeroutput"><span class="keyword">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="keyword">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 class="toc">
|
||
<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.implicit_params">Implicit
|
||
Parameters to Primitive Transforms</a></span></dt>
|
||
<dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.unpacking_expressions">Unpacking
|
||
Expressions</a></span></dt>
|
||
<dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.external_transforms">Separating
|
||
Grammars And 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 an embedded domain-specific
|
||
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
|
||
EDSL</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 EDSL 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="boost_proto.users_guide.back_end.expression_transformation.example__calculator_arity.t0"></a><p class="title"><b>Table 33.8. 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<a href="#ftn.boost_proto.users_guide.back_end.expression_transformation.example__calculator_arity.f0" class="footnote" name="boost_proto.users_guide.back_end.expression_transformation.example__calculator_arity.f0"><sup class="footnote">[35]</sup></a>:
|
||
</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.
|
||
</p>
|
||
<p>
|
||
Let's modify our previous example so that it writes each terminal to
|
||
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span></code> before it puts it into a list.
|
||
This could be handy for debugging your transforms, for instance. We can
|
||
make it general by passing a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ostream</span></code>
|
||
into the transform in the data parameter. Within the transform itself,
|
||
we can retrieve the <code class="computeroutput"><span class="identifier">ostream</span></code>
|
||
with the <code class="computeroutput"><a class="link" href="../boost/proto/_data.html" title="Struct _data">proto::_data</a></code>
|
||
transform. The strategy is as follows: use the <code class="computeroutput"><a class="link" href="../boost/proto/and_.html" title="Struct template and_">proto::and_<></a></code>
|
||
transform to chain two actions. The second action will create the <code class="computeroutput"><span class="identifier">fusion</span><span class="special">::</span><span class="identifier">cons</span><span class="special"><></span></code>
|
||
node as before. The first action, however, will display the current expression.
|
||
For that, we first construct an instance of <code class="computeroutput"><a class="link" href="../boost/proto/functional/display_expr.html" title="Struct display_expr">proto::functional::display_expr</a></code> and then call
|
||
it.
|
||
</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">proto</span><span class="special">::</span><span class="identifier">and_</span><span class="special"><</span>
|
||
<span class="comment">// First, write the terminal to an ostream passed</span>
|
||
<span class="comment">// in the data parameter</span>
|
||
<span class="identifier">proto</span><span class="special">::</span><span class="identifier">lazy</span><span class="special"><</span>
|
||
<span class="identifier">proto</span><span class="special">::</span><span class="identifier">make</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">display_expr</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">_</span><span class="special">)</span>
|
||
<span class="special">></span>
|
||
<span class="comment">// Then, constuct the new cons list.</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="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="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>
|
||
This is a lot to take in, no doubt. But focus on the second <code class="computeroutput"><span class="identifier">when</span></code> clause above. It says: when you
|
||
find a terminal, first display the terminal using the <code class="computeroutput"><span class="identifier">ostream</span></code>
|
||
you find in the data parameter, then take the value of the terminal and
|
||
the current state to build a new <code class="computeroutput"><span class="identifier">cons</span></code>
|
||
list. The function object <code class="computeroutput"><span class="identifier">display_expr</span></code>
|
||
does the job of printing the terminal, and <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">and_</span><span class="special"><></span></code> chains the actions together and
|
||
executes them in sequence, returning the result of the last one.
|
||
</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>
|
||
Also new is <code class="computeroutput"><a class="link" href="../boost/proto/lazy.html" title="Struct template lazy">proto::lazy<></a></code>. Sometimes you
|
||
don't have a ready-made callable object to execute. Instead, you want
|
||
to first make one and <span class="emphasis"><em>then</em></span> execute it. Above,
|
||
we need to create a <code class="computeroutput"><span class="identifier">display_expr</span></code>,
|
||
initializing it with our <code class="computeroutput"><span class="identifier">ostream</span></code>.
|
||
After that, we want to invoke it by passing it the current expression.
|
||
It's as if we were doing <code class="computeroutput"><span class="identifier">display_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="emphasis"><em>the-expr</em></span><span class="special">)</span></code>.
|
||
We achieve this two-phase evaluation using <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">lazy</span><span class="special"><></span></code>. If this doesn't make sense
|
||
yet, don't worry about it.
|
||
</p></td></tr>
|
||
</table></div>
|
||
<p>
|
||
We can use the above transform as before, but now we can pass an <code class="computeroutput"><span class="identifier">ostream</span></code> as the third parameter and
|
||
get to watch the transform in action. Here's a sample usage:
|
||
</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="comment">// Pass std::cout as the data parameter so that we can track</span>
|
||
<span class="comment">// the progress of the transform on the console.</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="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">);</span>
|
||
|
||
<span class="comment">// Now "args" is the list: {1, 3.14, '\n'}</span>
|
||
</pre>
|
||
<p>
|
||
This code displays the following:
|
||
</p>
|
||
<pre class="programlisting">terminal(
|
||
)
|
||
terminal(3.14)
|
||
terminal(1)</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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.back_end.expression_transformation.data.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.back_end.expression_transformation.data.transform_environment_variables"></a></span><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.data.transform_environment_variables">Transform
|
||
Environment Variables</a>
|
||
</h6>
|
||
<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="emphasis"><em>This is an advanced topic. Feel free to skip if you are new
|
||
to Proto.</em></span>
|
||
</p></td></tr>
|
||
</table></div>
|
||
<p>
|
||
The example above uses the data parameter as a transport mechanism for
|
||
an unstructured blob of data; in this case, a reference to an <code class="computeroutput"><span class="identifier">ostream</span></code>. As your Proto algorithms become
|
||
more sophisticated, you may find that an unstructured blob of data isn't
|
||
terribly convenient to work with. Different parts of your algorithm may
|
||
be interested in different bits of data. What you want, instead, is a
|
||
way to pass in a collection of <span class="emphasis"><em>environment variables</em></span>
|
||
to a transform, like a collection of key/value pairs. Then, you can easily
|
||
get at the piece of data you want by asking the data parameter for the
|
||
value associated with a particular key. Proto's <span class="emphasis"><em>transform environments</em></span>
|
||
give you just that.
|
||
</p>
|
||
<p>
|
||
Let's start by defining a key.
|
||
</p>
|
||
<pre class="programlisting"><span class="identifier">BOOST_PROTO_DEFINE_ENV_VAR</span><span class="special">(</span><span class="identifier">mykey_type</span><span class="special">,</span> <span class="identifier">mykey</span><span class="special">);</span>
|
||
</pre>
|
||
<p>
|
||
This defines a global constant <code class="computeroutput"><span class="identifier">mykey</span></code>
|
||
with the type <code class="computeroutput"><span class="identifier">mykey_type</span></code>.
|
||
We can use <code class="computeroutput"><span class="identifier">mykey</span></code> to store
|
||
a piece of assiciated data in a transform environment, as so:
|
||
</p>
|
||
<pre class="programlisting"><span class="comment">// Call the MyEval algorithm with a transform environment containing</span>
|
||
<span class="comment">// two key/value pairs: one for proto::data and one for mykey</span>
|
||
<span class="identifier">MyEval</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="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">data</span> <span class="special">=</span> <span class="number">42</span><span class="special">,</span> <span class="identifier">mykey</span> <span class="special">=</span> <span class="string">"hello world"</span><span class="special">)</span> <span class="special">);</span>
|
||
</pre>
|
||
<p>
|
||
The above means to invoke the <code class="computeroutput"><span class="identifier">MyEval</span></code>
|
||
algorithm with three parameters: an expression, an initial state, and
|
||
a transform environment containing two key/value pairs.
|
||
</p>
|
||
<p>
|
||
From within a Proto algorithm, you can access the values associated with
|
||
different keys using the <code class="computeroutput"><a class="link" href="../boost/proto/_env_var.html" title="Struct template _env_var">proto::_env_var<></a></code>
|
||
transform. For instance, <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_env_var</span><span class="special"><</span><span class="identifier">mykey_type</span><span class="special">></span></code> would fetch the value <code class="computeroutput"><span class="string">"hello world"</span></code> from the transform
|
||
environment created above.
|
||
</p>
|
||
<p>
|
||
The <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_data</span></code> transform has some additional
|
||
smarts. Rather than always returning the third parameter regarless of
|
||
whether it is a blob or a transform environment, it checks first to see
|
||
if it's a blob or not. If so, that's what gets returned. If not, it returns
|
||
the value associated with the <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">data</span></code>
|
||
key. In the above example, that would be the value <code class="computeroutput"><span class="number">42</span></code>.
|
||
</p>
|
||
<p>
|
||
There's a small host of functions, metafunction, and classes that you
|
||
can use to create and manipulate transform environments, some for testing
|
||
whether an object is a transform environment, some for coercing an object
|
||
to be a transform environment, and some for querying a transform environment
|
||
whether or not is has a value for a particular key. For an exhaustive
|
||
treatment of the topic, check out the reference for the <code class="computeroutput"><a class="link" href="reference.html#header.boost.proto.transform.env_hpp" title="Header <boost/proto/transform/env.hpp>">boost/proto/transform/env.hpp</a></code>
|
||
header.
|
||
</p>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h5 class="title">
|
||
<a name="boost_proto.users_guide.back_end.expression_transformation.implicit_params"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.implicit_params" title="Implicit Parameters to Primitive Transforms">Implicit
|
||
Parameters to Primitive Transforms</a>
|
||
</h5></div></div></div>
|
||
<p>
|
||
Let's use <code class="computeroutput"><span class="identifier">FoldToList</span></code>
|
||
example from the previous two sections 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 from
|
||
the last section:
|
||
</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">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="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">FoldToList</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">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">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="special">)</span>
|
||
</pre>
|
||
<p>
|
||
The same is true for any primitive transform. The following are all equivalent:
|
||
</p>
|
||
<div class="table">
|
||
<a name="boost_proto.users_guide.back_end.expression_transformation.implicit_params.t0"></a><p class="title"><b>Table 33.9. 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">FoldToList</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">FoldToList</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">FoldToList</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">FoldToList</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">FoldToList</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
|
||
for all your callable transforms. That would be an error. You can only
|
||
do that for primitive transforms, and not all callables are primitive
|
||
transforms. Later on, we'll see what distinguishes ordinary callables
|
||
from their more powerful primitive transfor cousins, but the short
|
||
version is this: primitive transforms inherit from <code class="computeroutput"><a class="link" href="../boost/proto/transform.html" title="Struct template transform">proto::transform<></a></code>.
|
||
</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="boost_proto.users_guide.back_end.expression_transformation.implicit_params.t1"></a><p class="title"><b>Table 33.10. 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::reverse_fold<></code>
|
||
</p>
|
||
</th>
|
||
<th>
|
||
<p>
|
||
With <code class="literal">proto::reverse_fold<></code>
|
||
</p>
|
||
</th>
|
||
</tr></thead>
|
||
<tbody><tr>
|
||
<td>
|
||
<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">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="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">reverse_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">FoldToList</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.unpacking_expressions"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.unpacking_expressions" title="Unpacking Expressions">Unpacking
|
||
Expressions</a>
|
||
</h5></div></div></div>
|
||
<p>
|
||
Processing expressions with an arbitrary number of children can be a
|
||
pain. What if you want to do something to each child, then pass the results
|
||
as arguments to some other function? Can you do it just once without
|
||
worrying about how many children an expression has? Yes. This is where
|
||
Proto's <span class="emphasis"><em>unpacking expressions</em></span> come in handy. Unpacking
|
||
expressions give you a way to write callable and object transforms that
|
||
handle <span class="emphasis"><em>n</em></span>-ary expressions.
|
||
</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>Inspired by C++11 Variadic Templates</strong></span>
|
||
</p>
|
||
<p>
|
||
Proto's unpacking expressions take inspiration from the C++11 feature
|
||
of the same name. If you are familiar with variadic functions, and
|
||
in particular how to expand a function parameter pack, this discussion
|
||
should seem very familiar. However, this feature doesn't actually use
|
||
any C++11 features, so the code describe here will work with any compliant
|
||
C++98 compiler.
|
||
</p>
|
||
</td></tr>
|
||
</table></div>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.back_end.expression_transformation.unpacking_expressions.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.back_end.expression_transformation.unpacking_expressions.example__a_c___expression_evaluator"></a></span><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.unpacking_expressions.example__a_c___expression_evaluator">Example:
|
||
A C++ Expression Evaluator</a>
|
||
</h6>
|
||
<p>
|
||
Proto has the built-in <code class="computeroutput"><a class="link" href="../boost/proto/_default.html" title="Struct template _default">proto::_default<></a></code>
|
||
transform for evaluating Proto expressions in a C++-ish way. But if it
|
||
didn't, it wouldn't be too hard to implement one from scratch using Proto's
|
||
unpacking patterns. The transform <code class="computeroutput"><span class="identifier">eval</span></code>
|
||
below does just that.
|
||
</p>
|
||
<pre class="programlisting"><span class="comment">// A callable polymorphic function object that takes an unpacked expression</span>
|
||
<span class="comment">// and a tag, and evaluates the expression. A plus tag and two operands adds</span>
|
||
<span class="comment">// them with operator +, for instance.</span>
|
||
<span class="keyword">struct</span> <span class="identifier">do_eval</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">double</span> <span class="identifier">result_type</span><span class="special">;</span>
|
||
|
||
<span class="preprocessor">#define</span> <span class="identifier">UNARY_OP</span><span class="special">(</span><span class="identifier">TAG</span><span class="special">,</span> <span class="identifier">OP</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="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">TAG</span><span class="special">,</span> <span class="identifier">Arg</span> <span class="identifier">arg</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">return</span> <span class="identifier">OP</span> <span class="identifier">arg</span><span class="special">;</span> <span class="special">\</span>
|
||
<span class="special">}</span> <span class="special">\</span>
|
||
<span class="comment">/**/</span>
|
||
|
||
<span class="preprocessor">#define</span> <span class="identifier">BINARY_OP</span><span class="special">(</span><span class="identifier">TAG</span><span class="special">,</span> <span class="identifier">OP</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">Left</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Right</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="identifier">proto</span><span class="special">::</span><span class="identifier">tag</span><span class="special">::</span><span class="identifier">TAG</span><span class="special">,</span> <span class="identifier">Left</span> <span class="identifier">left</span><span class="special">,</span> <span class="identifier">Right</span> <span class="identifier">right</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">return</span> <span class="identifier">left</span> <span class="identifier">OP</span> <span class="identifier">right</span><span class="special">;</span> <span class="special">\</span>
|
||
<span class="special">}</span> <span class="special">\</span>
|
||
<span class="comment">/**/</span>
|
||
|
||
<span class="identifier">UNARY_OP</span><span class="special">(</span><span class="identifier">negate</span><span class="special">,</span> <span class="special">-)</span>
|
||
<span class="identifier">BINARY_OP</span><span class="special">(</span><span class="identifier">plus</span><span class="special">,</span> <span class="special">+)</span>
|
||
<span class="identifier">BINARY_OP</span><span class="special">(</span><span class="identifier">minus</span><span class="special">,</span> <span class="special">-)</span>
|
||
<span class="identifier">BINARY_OP</span><span class="special">(</span><span class="identifier">multiplies</span><span class="special">,</span> <span class="special">*)</span>
|
||
<span class="identifier">BINARY_OP</span><span class="special">(</span><span class="identifier">divides</span><span class="special">,</span> <span class="special">/)</span>
|
||
<span class="comment">/*... others ...*/</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">or_</span><span class="special"><</span>
|
||
<span class="comment">// Evaluate terminals by simply returning their 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="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span><span class="special">></span>
|
||
|
||
<span class="comment">// Non-terminals are handled by unpacking the expression,</span>
|
||
<span class="comment">// recursively calling eval on each child, and passing</span>
|
||
<span class="comment">// the results along with the expression's tag to do_eval</span>
|
||
<span class="comment">// defined above.</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">do_eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag_of</span><span class="special"><</span><span class="identifier">_</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">pack</span><span class="special">(</span><span class="identifier">_</span><span class="special">))...)></span>
|
||
<span class="comment">// UNPACKING PATTERN HERE -------------------^^^^^^^^^^^^^^^^^^^^^^^^</span>
|
||
<span class="special">></span>
|
||
<span class="special">{};</span>
|
||
</pre>
|
||
<p>
|
||
The bulk of the above code is devoted to the <code class="computeroutput"><span class="identifier">do_eval</span></code>
|
||
function object that maps tag types to behaviors, but the interesting
|
||
bit is the definition of the <code class="computeroutput"><span class="identifier">eval</span></code>
|
||
algorithm at the bottom. Terminals are handled quite simply, but non-terminals
|
||
could be unary, binary, ternary, even <span class="emphasis"><em>n</em></span>-ary if we
|
||
consider function call expressions. The <code class="computeroutput"><span class="identifier">eval</span></code>
|
||
algorithm handles this uniformly with the help of an unpacking pattern.
|
||
</p>
|
||
<p>
|
||
Non-terminals are evaluated with this callable transform:
|
||
</p>
|
||
<pre class="programlisting"><span class="identifier">do_eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag_of</span><span class="special"><</span><span class="identifier">_</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">pack</span><span class="special">(</span><span class="identifier">_</span><span class="special">))...)</span>
|
||
</pre>
|
||
<p>
|
||
You can read this as: call the <code class="computeroutput"><span class="identifier">do_eval</span></code>
|
||
function object with the tag of the current expression and all its children
|
||
after they have each been evaluated with <code class="computeroutput"><span class="identifier">eval</span></code>.
|
||
The unpacking pattern is the bit just before the ellipsis: <code class="computeroutput"><span class="identifier">eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">pack</span><span class="special">(</span><span class="identifier">_</span><span class="special">))</span></code>.
|
||
</p>
|
||
<p>
|
||
What's going on here is this. The unpacking expression gets repeated
|
||
once for each child in the expression currently being evaluated. In each
|
||
repetition, the type <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">pack</span><span class="special">(</span><span class="identifier">_</span><span class="special">)</span></code> gets replaced with <code class="literal">proto::_child_c<<span class="emphasis"><em>N</em></span>></code>.
|
||
So, if a unary expression is passed to <code class="computeroutput"><span class="identifier">eval</span></code>,
|
||
it actually gets evaluated like this:
|
||
</p>
|
||
<pre class="programlisting"><span class="comment">// After the unpacking pattern is expanded for a unary expression</span>
|
||
<span class="identifier">do_eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag_of</span><span class="special"><</span><span class="identifier">_</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>
|
||
</pre>
|
||
<p>
|
||
And when passed a binary expression, the unpacking pattern expands like
|
||
this:
|
||
</p>
|
||
<pre class="programlisting"><span class="comment">// After the unpacking pattern is expanded for a binary expression</span>
|
||
<span class="identifier">do_eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag_of</span><span class="special"><</span><span class="identifier">_</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">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>
|
||
</pre>
|
||
<p>
|
||
Although it can't happen in our example, when passed a terminal, the
|
||
unpacking pattern expands such that it extracts the value from the terminal
|
||
instead of the children. So it gets handled like this:
|
||
</p>
|
||
<pre class="programlisting"><span class="comment">// If a terminal were passed to this transform, Proto would try</span>
|
||
<span class="comment">// to evaluate it like this, which would fail:</span>
|
||
<span class="identifier">do_eval</span><span class="special">(</span><span class="identifier">proto</span><span class="special">::</span><span class="identifier">tag_of</span><span class="special"><</span><span class="identifier">_</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">_value</span><span class="special">))</span>
|
||
</pre>
|
||
<p>
|
||
That doesn't make sense. <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_value</span></code>
|
||
would return something that isn't a Proto expression, and <code class="computeroutput"><span class="identifier">eval</span></code> wouldn't be able to evaluate it.
|
||
Proto algorithms don't work unless you pass them Proto expressions.
|
||
</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>Kickin' It Old School</strong></span>
|
||
</p>
|
||
<p>
|
||
You may be thinking, my compiler doesn't support C++11 variadic templates!
|
||
How can this possibly work? The answer is simple: The <code class="computeroutput"><span class="special">...</span></code> above isn't a C++11 pack expansion.
|
||
It's actually an old-school C-style vararg. Remember that callable
|
||
and object transforms are <span class="emphasis"><em>function types</em></span>. A transform
|
||
with one of these pseudo-pack expansions is really just the type of
|
||
a boring, old vararg function. Proto just interprets it differently.
|
||
</p>
|
||
</td></tr>
|
||
</table></div>
|
||
<p>
|
||
Unpacking patterns are very expressive. Any callable or object transform
|
||
can be used as an unpacking pattern, so long as <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">pack</span><span class="special">(</span><span class="identifier">_</span><span class="special">)</span></code> appears exactly once somewhere within
|
||
it. This gives you a lot of flexibility in how you want to process the
|
||
children of an expression before passing them on to some function object
|
||
or object constructor.
|
||
</p>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h5 class="title">
|
||
<a name="boost_proto.users_guide.back_end.expression_transformation.external_transforms"></a><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.external_transforms" title="Separating Grammars And Transforms">Separating
|
||
Grammars And Transforms</a>
|
||
</h5></div></div></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>
|
||
This is an advanced topic that is only necessary for people defining
|
||
large EDSLs. Feel free to skip this if you're just getting started
|
||
with Proto.
|
||
</p></td></tr>
|
||
</table></div>
|
||
<p>
|
||
So far, we've seen examples of grammars with embedded transforms. In
|
||
practice, grammars can get pretty large, and you may want to use them
|
||
to drive several different computations. For instance, you may have a
|
||
grammar for a linear algebra domain, and you may want to use it to compute
|
||
the shape of the result (vector or matrix?) and also to compute the result
|
||
optimally. You don't want to have to copy and paste the whole shebang
|
||
just to tweak one of the embedded transforms. What you want instead is
|
||
to define the grammar once, and specify the transforms later when you're
|
||
ready to evaluate an expression. For that, you use <span class="emphasis"><em>external
|
||
transforms</em></span>. The pattern you'll use is this: replace one or
|
||
more of the transforms in your grammar with the special placeholder
|
||
<code class="computeroutput"><a class="link" href="../boost/proto/external_transform.html" title="Struct external_transform">proto::external_transform</a></code>.
|
||
Then, you'll create a bundle of transforms that you will pass to the
|
||
grammar in the data parameter (the 3rd parameter after the expression
|
||
and state) when evaluating it.
|
||
</p>
|
||
<p>
|
||
To illustrate external transforms, we'll build a calculator evaluator
|
||
that can be configured to throw an exception on division by zero. Here
|
||
is a bare-bones front end that defines a domain, a grammar, an expression
|
||
wrapper, and some placeholder terminals.
|
||
</p>
|
||
<pre class="programlisting"><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">fusion</span><span class="special">/</span><span class="identifier">container</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">container</span><span class="special">/</span><span class="identifier">generation</span><span class="special">/</span><span class="identifier">make_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">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="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="comment">// The argument placeholder type</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">// The grammar for valid calculator expressions</span>
|
||
<span class="keyword">struct</span> <span class="identifier">calc_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">terminal</span><span class="special"><</span><span class="identifier">placeholder</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="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">plus</span><span class="special"><</span><span class="identifier">calc_grammar</span><span class="special">,</span> <span class="identifier">calc_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">calc_grammar</span><span class="special">,</span> <span class="identifier">calc_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">calc_grammar</span><span class="special">,</span> <span class="identifier">calc_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">calc_grammar</span><span class="special">,</span> <span class="identifier">calc_grammar</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">E</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">calc_expr</span><span class="special">;</span>
|
||
<span class="keyword">struct</span> <span class="identifier">calc_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">calc_expr</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">E</span><span class="special">></span>
|
||
<span class="keyword">struct</span> <span class="identifier">calc_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">calc_expr</span><span class="special"><</span><span class="identifier">E</span><span class="special">>,</span> <span class="identifier">calc_domain</span><span class="special">></span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">calc_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="identifier">E</span><span class="special">())</span> <span class="special">:</span> <span class="identifier">calc_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="special">};</span>
|
||
|
||
<span class="identifier">calc_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">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="identifier">_1</span><span class="special">;</span>
|
||
<span class="identifier">calc_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">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="identifier">_2</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">// Build a calculator expression, and do nothing with it.</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>
|
||
</pre>
|
||
<p>
|
||
Now, let's embed transforms into <code class="computeroutput"><span class="identifier">calc_grammar</span></code>
|
||
so that we can use it to evaluate calculator expressions:
|
||
</p>
|
||
<pre class="programlisting"><span class="comment">// The calculator grammar with embedded transforms for evaluating expression.</span>
|
||
<span class="keyword">struct</span> <span class="identifier">calc_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">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">proto</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">functional</span><span class="special">::</span><span class="identifier">at</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="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="keyword">int</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="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">calc_grammar</span><span class="special">,</span> <span class="identifier">calc_grammar</span><span class="special">></span>
|
||
<span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_default</span><span class="special"><</span><span class="identifier">calc_grammar</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">minus</span><span class="special"><</span><span class="identifier">calc_grammar</span><span class="special">,</span> <span class="identifier">calc_grammar</span><span class="special">></span>
|
||
<span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_default</span><span class="special"><</span><span class="identifier">calc_grammar</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">multiplies</span><span class="special"><</span><span class="identifier">calc_grammar</span><span class="special">,</span> <span class="identifier">calc_grammar</span><span class="special">></span>
|
||
<span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_default</span><span class="special"><</span><span class="identifier">calc_grammar</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">divides</span><span class="special"><</span><span class="identifier">calc_grammar</span><span class="special">,</span> <span class="identifier">calc_grammar</span><span class="special">></span>
|
||
<span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_default</span><span class="special"><</span><span class="identifier">calc_grammar</span><span class="special">></span>
|
||
<span class="special">></span>
|
||
<span class="special">></span>
|
||
<span class="special">{};</span>
|
||
</pre>
|
||
<p>
|
||
With this definition of <code class="computeroutput"><span class="identifier">calc_grammar</span></code>
|
||
we can evaluate expressions by passing along a Fusion vector containing
|
||
the values to use for the <code class="computeroutput"><span class="identifier">_1</span></code>
|
||
and <code class="computeroutput"><span class="identifier">_2</span></code> placeholders:
|
||
</p>
|
||
<pre class="programlisting"><span class="keyword">int</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">calc_grammar</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">fusion</span><span class="special">::</span><span class="identifier">make_vector</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">BOOST_ASSERT</span><span class="special">(</span><span class="identifier">result</span> <span class="special">==</span> <span class="number">7</span><span class="special">);</span>
|
||
</pre>
|
||
<p>
|
||
We also want an alternative evaluation strategy that checks for division
|
||
by zero and throws an exception. Just how ridiculous would it be to copy
|
||
the entire <code class="computeroutput"><span class="identifier">calc_grammar</span></code>
|
||
just to change the one line that transforms division expressions?! External
|
||
transforms are ideally suited to this problem.
|
||
</p>
|
||
<p>
|
||
First, we give the division rule in our grammar a "name"; that
|
||
is, we make it a struct. We'll use this unique type later to dispatch
|
||
to the right transforms.
|
||
</p>
|
||
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">calc_grammar</span><span class="special">;</span>
|
||
<span class="keyword">struct</span> <span class="identifier">divides_rule</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">calc_grammar</span><span class="special">,</span> <span class="identifier">calc_grammar</span><span class="special">></span> <span class="special">{};</span>
|
||
</pre>
|
||
<p>
|
||
Next, we change <code class="computeroutput"><span class="identifier">calc_grammar</span></code>
|
||
to make the handling of division expressions external.
|
||
</p>
|
||
<pre class="programlisting"><span class="comment">// The calculator grammar with an external transform for evaluating</span>
|
||
<span class="comment">// division expressions.</span>
|
||
<span class="keyword">struct</span> <span class="identifier">calc_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="comment">/* ... as before ... */</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">divides_rule</span>
|
||
<span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">external_transform</span>
|
||
<span class="special">></span>
|
||
<span class="special">></span>
|
||
<span class="special">{};</span>
|
||
</pre>
|
||
<p>
|
||
The use of <code class="computeroutput"><a class="link" href="../boost/proto/external_transform.html" title="Struct external_transform">proto::external_transform</a></code> above
|
||
makes the handling of division expressions externally parameterizeable.
|
||
</p>
|
||
<p>
|
||
Next, we use <code class="computeroutput"><a class="link" href="../boost/proto/external_transforms.html" title="Struct template external_transforms">proto::external_transforms<></a></code>
|
||
(note the trailing 's') to capture our evaluation strategy in a bundle
|
||
that we can pass along to the transform in the data parameter. Read on
|
||
for the explanation.
|
||
</p>
|
||
<pre class="programlisting"><span class="comment">// Evaluate division nodes as before</span>
|
||
<span class="keyword">struct</span> <span class="identifier">non_checked_division</span>
|
||
<span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">external_transforms</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">divides_rule</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_default</span><span class="special"><</span><span class="identifier">calc_grammar</span><span class="special">></span> <span class="special">></span>
|
||
<span class="special">></span>
|
||
<span class="special">{};</span>
|
||
|
||
<span class="comment">/* ... */</span>
|
||
|
||
<span class="identifier">non_checked_division</span> <span class="identifier">non_checked</span><span class="special">;</span>
|
||
<span class="keyword">int</span> <span class="identifier">result2</span> <span class="special">=</span> <span class="identifier">calc_grammar</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">fusion</span><span class="special">::</span><span class="identifier">make_vector</span><span class="special">(</span><span class="number">6</span><span class="special">,</span> <span class="number">2</span><span class="special">),</span> <span class="identifier">non_checked</span><span class="special">);</span>
|
||
</pre>
|
||
<p>
|
||
The struct <code class="computeroutput"><span class="identifier">non_cecked_division</span></code>
|
||
associates the transform <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">_default</span><span class="special"><</span><span class="identifier">calc_grammar</span><span class="special">></span></code> with the <code class="computeroutput"><span class="identifier">divides_rule</span></code>
|
||
grammar rule. An instance of that struct is passed along as the third
|
||
parameter when invoking <code class="computeroutput"><span class="identifier">calc_grammar</span></code>.
|
||
</p>
|
||
<p>
|
||
Now, let's implement checked division. The rest should be unsurprising.
|
||
</p>
|
||
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">division_by_zero</span> <span class="special">:</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">exception</span> <span class="special">{};</span>
|
||
|
||
<span class="keyword">struct</span> <span class="identifier">do_checked_divide</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">int</span> <span class="identifier">result_type</span><span class="special">;</span>
|
||
<span class="keyword">int</span> <span class="keyword">operator</span><span class="special">()(</span><span class="keyword">int</span> <span class="identifier">left</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">right</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">right</span> <span class="special">==</span> <span class="number">0</span><span class="special">)</span> <span class="keyword">throw</span> <span class="identifier">division_by_zero</span><span class="special">();</span>
|
||
<span class="keyword">return</span> <span class="identifier">left</span> <span class="special">/</span> <span class="identifier">right</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="special">};</span>
|
||
|
||
<span class="keyword">struct</span> <span class="identifier">checked_division</span>
|
||
<span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">external_transforms</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">divides_rule</span>
|
||
<span class="special">,</span> <span class="identifier">do_checked_divide</span><span class="special">(</span><span class="identifier">calc_grammar</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">calc_grammar</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>
|
||
|
||
<span class="comment">/* ... */</span>
|
||
|
||
<span class="keyword">try</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">checked_division</span> <span class="identifier">checked</span><span class="special">;</span>
|
||
<span class="keyword">int</span> <span class="identifier">result3</span> <span class="special">=</span> <span class="identifier">calc_grammar_extern</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">fusion</span><span class="special">::</span><span class="identifier">make_vector</span><span class="special">(</span><span class="number">6</span><span class="special">,</span> <span class="number">0</span><span class="special">),</span> <span class="identifier">checked</span><span class="special">);</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">catch</span><span class="special">(</span><span class="identifier">division_by_zero</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">"caught division by zero!\n"</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
</pre>
|
||
<p>
|
||
The above code demonstrates how a single grammar can be used with different
|
||
transforms specified externally. This makes it possible to reuse a grammar
|
||
to drive several different computations.
|
||
</p>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.back_end.expression_transformation.external_transforms.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.back_end.expression_transformation.external_transforms.separating_data_from_external_transforms"></a></span><a class="link" href="users_guide.html#boost_proto.users_guide.back_end.expression_transformation.external_transforms.separating_data_from_external_transforms">Separating
|
||
Data From External Transforms</a>
|
||
</h6>
|
||
<p>
|
||
As described above, the external transforms feature usurps the data parameter,
|
||
which is intended to be a place where you can pass arbitrary data, and
|
||
gives it a specific meaning. But what if you are already using the data
|
||
parameter for something else? The answer is to use a transform environment.
|
||
By associating your external transforms with the <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">transforms</span></code>
|
||
key, you are free to pass arbitrary data in other slots.
|
||
</p>
|
||
<p>
|
||
To continue the above example, what if we also needed to pass a piece
|
||
of data into our transform along with the external transforms? It would
|
||
look like this:
|
||
</p>
|
||
<pre class="programlisting"><span class="keyword">int</span> <span class="identifier">result3</span> <span class="special">=</span> <span class="identifier">calc_grammar_extern</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">fusion</span><span class="special">::</span><span class="identifier">make_vector</span><span class="special">(</span><span class="number">6</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">data</span> <span class="special">=</span> <span class="number">42</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">transforms</span> <span class="special">=</span> <span class="identifier">checked</span><span class="special">)</span>
|
||
<span class="special">);</span>
|
||
</pre>
|
||
<p>
|
||
In the above invocation of the <code class="computeroutput"><span class="identifier">calc_grammar_extern</span></code>
|
||
algorithm, the map of external transforms is associated with the <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">transforms</span></code> key and passed to the algorithm
|
||
in a transform environment. Also in the transform environment is a key/value
|
||
pair that associates the value <code class="computeroutput"><span class="number">42</span></code>
|
||
with the <code class="computeroutput"><span class="identifier">proto</span><span class="special">::</span><span class="identifier">data</span></code> key.
|
||
</p>
|
||
</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 class="variablelist">
|
||
<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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.back_end.expression_transformation.canned_transforms.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.back_end.expression_transformation.canned_transforms.all_grammars_are_primitive_transforms"></a></span><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 class="variablelist">
|
||
<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>
|
||
<h6>
|
||
<a name="boost_proto.users_guide.back_end.expression_transformation.canned_transforms.h1"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.back_end.expression_transformation.canned_transforms.the_pass_through_transform"></a></span><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="boost_proto.users_guide.back_end.expression_transformation.canned_transforms.t0"></a><p class="title"><b>Table 33.11. 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"><h6>
|
||
<a name="boost_proto.users_guide.back_end.expression_transformation.canned_transforms.h2"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.back_end.expression_transformation.canned_transforms.the_many_roles_of_proto_operator_metafunctions"></a></span><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="boost_proto.users_guide.back_end.expression_transformation.primitives.t0"></a><p class="title"><b>Table 33.12. 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 class="toc">
|
||
<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>
|
||
<dt><span class="section"><a href="users_guide.html#boost_proto.users_guide.examples.checked_calc">Checked
|
||
Calculator: A Simple Example of External Transforms</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 embedded domain-specific 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="identifier">Expr</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="identifier">Expr</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://acts.nersc.gov/formertools/pete/index.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://acts.nersc.gov/formertools/pete/index.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://acts.nersc.gov/formertools/pete/index.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="comment">// This copy-assign is needed because a template is never</span>
|
||
<span class="comment">// considered for copy assignment.</span>
|
||
<span class="identifier">Vec3</span> <span class="special">&</span><span class="keyword">operator</span><span class="special">=(</span><span class="identifier">Vec3</span> <span class="keyword">const</span> <span class="special">&</span><span class="identifier">that</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">that</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">that</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">that</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://acts.nersc.gov/formertools/pete/index.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://acts.nersc.gov/formertools/pete/index.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="comment">// map_list_of(a,b)</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="comment">// map_list_of(a,b)(c,d)...</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
|
||
EDSL 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">// following 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 class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="boost_proto.users_guide.examples.checked_calc"></a><a class="link" href="users_guide.html#boost_proto.users_guide.examples.checked_calc" title="Checked Calculator: A Simple Example of External Transforms">Checked
|
||
Calculator: A Simple Example of External Transforms</a>
|
||
</h4></div></div></div>
|
||
<p>
|
||
This is an advanced example that shows how to externally parameterize a
|
||
grammar's transforms. It defines a calculator EDSL with a grammar that
|
||
can perform either checked or unchecked arithmetic.
|
||
</p>
|
||
<p>
|
||
</p>
|
||
<pre class="programlisting"><span class="comment">// Copyright 2011 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 how to specify a transform externally so</span>
|
||
<span class="comment">// that a single grammar can be used to drive multiple differnt</span>
|
||
<span class="comment">// calculations. In particular, it defines a calculator grammar</span>
|
||
<span class="comment">// that computes the result of an expression with either checked</span>
|
||
<span class="comment">// or non-checked division.</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">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">mpl</span><span class="special">/</span><span class="identifier">next</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">fusion</span><span class="special">/</span><span class="identifier">container</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">container</span><span class="special">/</span><span class="identifier">generation</span><span class="special">/</span><span class="identifier">make_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">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="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="comment">// The argument placeholder type</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">// Give each rule in the grammar a "name". This is so that we</span>
|
||
<span class="comment">// can easily dispatch on it later.</span>
|
||
<span class="keyword">struct</span> <span class="identifier">calc_grammar</span><span class="special">;</span>
|
||
<span class="keyword">struct</span> <span class="identifier">divides_rule</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">calc_grammar</span><span class="special">,</span> <span class="identifier">calc_grammar</span><span class="special">></span> <span class="special">{};</span>
|
||
|
||
<span class="comment">// Use external transforms in calc_gramar</span>
|
||
<span class="keyword">struct</span> <span class="identifier">calc_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">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">proto</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">functional</span><span class="special">::</span><span class="identifier">at</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="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">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="identifier">proto</span><span class="special">::</span><span class="identifier">_value</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">calc_grammar</span><span class="special">,</span> <span class="identifier">calc_grammar</span><span class="special">></span>
|
||
<span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_default</span><span class="special"><</span><span class="identifier">calc_grammar</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">minus</span><span class="special"><</span><span class="identifier">calc_grammar</span><span class="special">,</span> <span class="identifier">calc_grammar</span><span class="special">></span>
|
||
<span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_default</span><span class="special"><</span><span class="identifier">calc_grammar</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">multiplies</span><span class="special"><</span><span class="identifier">calc_grammar</span><span class="special">,</span> <span class="identifier">calc_grammar</span><span class="special">></span>
|
||
<span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_default</span><span class="special"><</span><span class="identifier">calc_grammar</span><span class="special">></span>
|
||
<span class="special">></span>
|
||
<span class="comment">// Note that we don't specify how division nodes are</span>
|
||
<span class="comment">// handled here. Proto::external_transform is a placeholder</span>
|
||
<span class="comment">// for an actual transform.</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">divides_rule</span>
|
||
<span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">external_transform</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">E</span><span class="special">></span> <span class="keyword">struct</span> <span class="identifier">calc_expr</span><span class="special">;</span>
|
||
<span class="keyword">struct</span> <span class="identifier">calc_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">calc_expr</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">E</span><span class="special">></span>
|
||
<span class="keyword">struct</span> <span class="identifier">calc_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">calc_expr</span><span class="special"><</span><span class="identifier">E</span><span class="special">>,</span> <span class="identifier">calc_domain</span><span class="special">></span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">calc_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="identifier">E</span><span class="special">())</span> <span class="special">:</span> <span class="identifier">calc_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="special">};</span>
|
||
|
||
<span class="identifier">calc_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">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="identifier">_1</span><span class="special">;</span>
|
||
<span class="identifier">calc_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">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="identifier">_2</span><span class="special">;</span>
|
||
|
||
<span class="comment">// Use proto::external_transforms to map from named grammar rules to</span>
|
||
<span class="comment">// transforms.</span>
|
||
<span class="keyword">struct</span> <span class="identifier">non_checked_division</span>
|
||
<span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">external_transforms</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">divides_rule</span><span class="special">,</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">_default</span><span class="special"><</span><span class="identifier">calc_grammar</span><span class="special">></span> <span class="special">></span>
|
||
<span class="special">></span>
|
||
<span class="special">{};</span>
|
||
|
||
<span class="keyword">struct</span> <span class="identifier">division_by_zero</span> <span class="special">:</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">exception</span> <span class="special">{};</span>
|
||
|
||
<span class="keyword">struct</span> <span class="identifier">do_checked_divide</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">int</span> <span class="identifier">result_type</span><span class="special">;</span>
|
||
<span class="keyword">int</span> <span class="keyword">operator</span><span class="special">()(</span><span class="keyword">int</span> <span class="identifier">left</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">right</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">right</span> <span class="special">==</span> <span class="number">0</span><span class="special">)</span> <span class="keyword">throw</span> <span class="identifier">division_by_zero</span><span class="special">();</span>
|
||
<span class="keyword">return</span> <span class="identifier">left</span> <span class="special">/</span> <span class="identifier">right</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="special">};</span>
|
||
|
||
<span class="comment">// Use proto::external_transforms again, this time to map the divides_rule</span>
|
||
<span class="comment">// to a transforms that performs checked division.</span>
|
||
<span class="keyword">struct</span> <span class="identifier">checked_division</span>
|
||
<span class="special">:</span> <span class="identifier">proto</span><span class="special">::</span><span class="identifier">external_transforms</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">divides_rule</span>
|
||
<span class="special">,</span> <span class="identifier">do_checked_divide</span><span class="special">(</span><span class="identifier">calc_grammar</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">calc_grammar</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>
|
||
|
||
<span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">non_checked_division</span> <span class="identifier">non_checked</span><span class="special">;</span>
|
||
<span class="keyword">int</span> <span class="identifier">result2</span> <span class="special">=</span> <span class="identifier">calc_grammar</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">fusion</span><span class="special">::</span><span class="identifier">make_vector</span><span class="special">(</span><span class="number">6</span><span class="special">,</span> <span class="number">2</span><span class="special">),</span> <span class="identifier">non_checked</span><span class="special">);</span>
|
||
<span class="identifier">BOOST_ASSERT</span><span class="special">(</span><span class="identifier">result2</span> <span class="special">==</span> <span class="number">3</span><span class="special">);</span>
|
||
|
||
<span class="keyword">try</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">checked_division</span> <span class="identifier">checked</span><span class="special">;</span>
|
||
<span class="comment">// This should throw</span>
|
||
<span class="keyword">int</span> <span class="identifier">result3</span> <span class="special">=</span> <span class="identifier">calc_grammar</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">fusion</span><span class="special">::</span><span class="identifier">make_vector</span><span class="special">(</span><span class="number">6</span><span class="special">,</span> <span class="number">0</span><span class="special">),</span> <span class="identifier">checked</span><span class="special">);</span>
|
||
<span class="identifier">BOOST_ASSERT</span><span class="special">(</span><span class="keyword">false</span><span class="special">);</span> <span class="comment">// shouldn't get here!</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">catch</span><span class="special">(</span><span class="identifier">division_by_zero</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">"caught division by zero!\n"</span><span class="special">;</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 EDSL 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>
|
||
<h5>
|
||
<a name="boost_proto.users_guide.resources.h0"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.resources.references"></a></span><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>
|
||
<h5>
|
||
<a name="boost_proto.users_guide.resources.h1"></a>
|
||
<span class="phrase"><a name="boost_proto.users_guide.resources.further_reading"></a></span><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 class="variablelist">
|
||
<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.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.edsl"></a> embedded domain-specific 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.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 embedded domain-specific 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.subdomain"></a> sub-domain</span></dt>
|
||
<dd><p>
|
||
A sub-domain is a domain that declares another domain as its super-domain.
|
||
Expressions in sub-domains can be combined with expressions in the
|
||
super-domain, and the resulting expression is in the super-domain.
|
||
</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 style="width:100; text-align:left;margin-left: 0">
|
||
<div id="ftn.boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child.f0" class="footnote"><p><a href="#boost_proto.users_guide.front_end.customizing_expressions_in_your_domain.per_domain_as_child.f0" class="para"><sup class="para">[34] </sup></a>
|
||
It's not always possible to hold something by value. By default, <code class="computeroutput"><a class="link" href="../boost/proto/as_expr.html" title="Function as_expr">proto::as_expr()</a></code> makes an exception
|
||
for functions, abstract types, and iostreams (types derived from <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">ios_base</span></code>). These objects are held
|
||
by reference. All others are held by value, even arrays.
|
||
</p></div>
|
||
<div id="ftn.boost_proto.users_guide.back_end.expression_transformation.example__calculator_arity.f0" class="footnote"><p><a href="#boost_proto.users_guide.back_end.expression_transformation.example__calculator_arity.f0" class="para"><sup class="para">[35] </sup></a>
|
||
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>
|