Boost logo

Boost-Commit :

From: eric_at_[hidden]
Date: 2008-02-01 15:30:30

Author: eric_niebler
Date: 2008-02-01 15:30:29 EST (Fri, 01 Feb 2008)
New Revision: 43050

add future group example
   trunk/libs/xpressive/proto/example/futures.cpp (contents, props changed)
Text files modified:
   trunk/libs/xpressive/proto/doc/calculator.qbk | 2
   trunk/libs/xpressive/proto/doc/construction.qbk | 33 +++++++-------
   trunk/libs/xpressive/proto/doc/evaluation.qbk | 15 ++++++
   trunk/libs/xpressive/proto/doc/examples.qbk | 87 ++++++++++++++++++++++++++++++++++-----
   trunk/libs/xpressive/proto/doc/installation.qbk | 5 +
   trunk/libs/xpressive/proto/doc/rationale.qbk | 30 +++++++++++++
   trunk/libs/xpressive/proto/example/Jamfile.v2 | 5 ++
   7 files changed, 144 insertions(+), 33 deletions(-)

Modified: trunk/libs/xpressive/proto/doc/calculator.qbk
--- trunk/libs/xpressive/proto/doc/calculator.qbk (original)
+++ trunk/libs/xpressive/proto/doc/calculator.qbk 2008-02-01 15:30:29 EST (Fri, 01 Feb 2008)
@@ -19,7 +19,7 @@
 [heading Defining Terminals]
 The first order of business is to define the placeholders `_1` and `_2`. For
-that, we'll use the _terminal_ expression generator.
+that, we'll use the _terminal_ metafuntion.
     // Define some placeholder types
     struct placeholder1 {};

Modified: trunk/libs/xpressive/proto/doc/construction.qbk
--- trunk/libs/xpressive/proto/doc/construction.qbk (original)
+++ trunk/libs/xpressive/proto/doc/construction.qbk 2008-02-01 15:30:29 EST (Fri, 01 Feb 2008)
@@ -351,16 +351,16 @@
 Below are the tools and a brief description of each.
-[ [`make_expr()`]
+[ [_make_expr_]
   [A function that takes a tag type and children nodes and
    builds a parent node of the requested type.]]
-[ [`unpack_expr()`]
- [A function that does the same as `make_expr()` except
+[ [_unpack_expr_]
+ [A function that does the same as _make_expr_ except
    the children nodes are specified as a Fusion sequence.]]
   [A macro that generates a number of overloads of a
    user-specified function template that behaves like
- `make_expr()`.]]
+ _make_expr_.]]
@@ -412,7 +412,7 @@
         make_expr(A const &... a);
-You can use the `make_expr()` function to build an expression tree node with
+You can use the _make_expr_ function to build an expression tree node with
 a specified tag type, as follows.
     // Some user-defined tag type
@@ -476,7 +476,7 @@
 In the return type calculation, we can specify by-ref with
 `int &`, but we need `boost::ref()` in the actual function invocation.
-That's because the `make_expr()` function can't tell from the function
+That's because the _make_expr_ function can't tell from the function
 arguments whether you want to store the arguments by value or by
@@ -509,10 +509,10 @@
     posit_ref_type p3 = +expr;
 The application of unary `operator+` on the last line is equivalent to
-the by-ref invocation of `make_expr()` because Proto's operator overloads
+the by-ref invocation of _make_expr_ because Proto's operator overloads
 always build trees by holding nodes by reference.
-If you specify a domain when invoking `make_expr()`, then `make_expr()`
+If you specify a domain when invoking _make_expr_, then _make_expr_
 will use that domain's generator to wrap the resulting node in a
 domain-specific wrapper. In the example below, expressions within the
 `MyDomain` domain are wrapped in a `MyExpr<>` wrapper.
@@ -602,7 +602,7 @@
         unpack_expr(Sequence const &sequence);
-Once you understand `make_expr()`, understanding `unpack_expr()` is
+Once you understand _make_expr_, understanding _unpack_expr_ is
 simple. It behaves exactly the same way, except that rather than
 passing children individually, you pass the children as a Fusion
 sequence. So for instance, the following are equivalent:
@@ -619,7 +619,7 @@
 If you would like the arguments to be stored by reference, you can
-use `boost::ref()`, just as with `make_expr()`.
+use `boost::ref()`, just as with _make_expr_.
     // Hold one argument by reference:
     int i = 0;
@@ -629,21 +629,21 @@
     fusion::tuple<int &, char> args(i, 'a');
-As with `make_expr()`, `unpack_expr()` has a corresponding metafunction
+As with _make_expr_, _unpack_expr_ has a corresponding metafunction
 in the `proto::result_of` namespace for calculating its return type, as
 well as a callable function object form in the `proto::functional`
-One last interesting point about `unpack_expr()`: Proto expression
+One last interesting point about _unpack_expr_: Proto expression
 nodes are themselves valid Fusion sequences. Here, for instance, is
-a clever way to use `unpack_expr()` to turn a binary plus node into
+a clever way to use _unpack_expr_ to turn a binary plus node into
 a binary minus node:
     // Use unpack_expr() to turn an addition into a subtraction
     proto::literal<int> i(8), j(42);
     proto::unpack_expr<proto::tag::minus>( i + j );
-The expression `i + j` creates an expression tree which `unpack_expr()`
+The expression `i + j` creates an expression tree which _unpack_expr_
 interprets as a sequence of its children `i` and `j`. The result is a
 new node with the `tag::minus` tag and `i` and `j` as children.
@@ -802,7 +802,8 @@
 Now users can say `construct<S>(_1, _2)` and get the lazy object
 construction they want. (Making it work with `std::transform()`
-takes a little more effort, but that's covered in the Calc3 example.)
+takes a little more effort, but that's covered in the
+[link boost_proto.users_guide.examples.calc2 Calc2] example.)
 Now we need /N/ overloads to handle up to /N/ arguments. That's a lot
 of boiler plate, so we can use the `BOOST_PROTO_DEFINE_VARARG_FUNCTION_TEMPLATE()`
 macro to simplify our job.
@@ -822,7 +823,7 @@
 The fourth argument to the macro is actually a PP sequence of PP
 sequences. Each sequence describes one implicit argument.
-[note [*Ugly Macros]
+[blurb [*Ugly Macros]
 You may find this use of the preprocessor distasteful and decide to
 write out the overloads yourself. That's fine, but there are some good

Modified: trunk/libs/xpressive/proto/doc/evaluation.qbk
--- trunk/libs/xpressive/proto/doc/evaluation.qbk (original)
+++ trunk/libs/xpressive/proto/doc/evaluation.qbk 2008-02-01 15:30:29 EST (Fri, 01 Feb 2008)
@@ -7,33 +7,46 @@
 [section:expression_evaluation Expression Evaluation: Imparting Behaviors Within A Context]
 [section:proto_eval Evaluating An Expression with [^proto::eval()]]
 [section:contexts Defining an Evaluation Context]
 [section:canned_contexts Canned Contexts]
 [section:default_context [^default_context]]
 [section:null_context [^null_context]]
 [section:callable_context [^callable_context<>]]

Modified: trunk/libs/xpressive/proto/doc/examples.qbk
--- trunk/libs/xpressive/proto/doc/examples.qbk (original)
+++ trunk/libs/xpressive/proto/doc/examples.qbk 2008-02-01 15:30:29 EST (Fri, 01 Feb 2008)
@@ -15,71 +15,132 @@
 [import ../example/tarray.cpp]
 [import ../example/vec3.cpp]
 [import ../example/vector.cpp]
+[import ../example/futures.cpp]
 [section Examples]
-[section Hello World]
+A code example is worth a thousand words ...
-blah blah blah
+[section:hello_world Hello World]
+A trivial example which builds and expression template
+and evaluates it.
-blah blah blah
-[section Calc1]
+[section:calc1 Calc1]
+A simple example which builds a miniature domain-specific
+embedded language for lazy arithmetic expressions, with
+TR1 bind-style argument placeholders.
-[section Calc2]
+[section:calc2 Calc2]
+An extension of the Calc1 example that uses _extends_ to
+make calculator expressions valid function objects that
+can be used with STL algorithms.
-[section Calc3]
+[section:calc3 Calc3]
+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 argument are passed.
-[section Lazy Vector]
+[section:lazy_vector Lazy Vector]
-[section RGB]
+[section:rgb RGB]
-[section TArray]
+[section:tarray TArray]
-[section Vec3]
+[section:vec3 Vec3]
-[section Vector]
+[section:vector Vector]
-[section Mixed]
+[section:mixed Mixed]
+[section:future_group Future Group]
+An advanced example of a Proto transform that implements
+Howard Hinnant's design for /future groups/ that block
+for all or some asynchronous operations to complete and
+returns their results in a tuple of the appropriate type.

Modified: trunk/libs/xpressive/proto/doc/installation.qbk
--- trunk/libs/xpressive/proto/doc/installation.qbk (original)
+++ trunk/libs/xpressive/proto/doc/installation.qbk 2008-02-01 15:30:29 EST (Fri, 01 Feb 2008)
@@ -20,10 +20,13 @@
 to do is `#include <boost/xpressive/proto/proto.hpp>`. This will include the
 core of Proto. If you want to use any transforms, you must include the
 appropriate header from the [^boost\/xpressive\/proto\/transform\/] directory.
+Likewise for any evaluation contexts, which live in the
+[^boost\/xpressive\/proto\/context\/] directory.
 [heading Requirements]
-Proto depends on Boost. You must use the version in SVN HEAD.
+Proto depends on Boost. You must use either Boost version 1.34.1 or the
+version in SVN trunk.
 [heading Supported Compilers]

Modified: trunk/libs/xpressive/proto/doc/rationale.qbk
--- trunk/libs/xpressive/proto/doc/rationale.qbk (original)
+++ trunk/libs/xpressive/proto/doc/rationale.qbk 2008-02-01 15:30:29 EST (Fri, 01 Feb 2008)
@@ -7,7 +7,9 @@
 [section:rationale Appendix B: Rationale]
 [section:static_initialization Static Initialization]
 Proto expression types are PODs (Plain Old Data), and do not have constructors.
 They are brace-initialized, as follows:
@@ -17,14 +19,16 @@
 The reason is so that expression objects like `_i` above can be ['statically
 initialized]. Why is static initialization important? The terminals of many
 domain-specific embedded languages are likely to be global const objects, like
-`_1` and `_2` from the Boost.Lambda library. Were these object to require
+`_1` and `_2` from the Boost Lambda Library. Were these object to require
 run-time initialization, it might be possible to use these objects before they
 are initialized. That would be bad. Statically initialized objects cannot be
 misused that way.
 [section:result_of Proto Transforms and the Restricted ResultOf Protocol]
 All Proto primitive transforms make use of a variant of the TR1 ResultOf
 protocol for computing the type of the transform's return value. Such
@@ -68,4 +72,28 @@
+[section:preprocessor Why Not Reuse MPL, Fusion, et cetera?]
+Anyone who has peeked at Proto's source code has probably wondered,
+"Why all the dirty preprocessor gunk? Couldn't this have been all
+implemented cleanly on top of libraries like MPL and Fusion?" The
+answer is that Proto could have been implement this way, and in fact
+was at one point. The problem is that template metaprogramming (TMP)
+makes for very long compile times. As a foundation upon which other
+TMP-heavy libraries will be built, Proto itself should be as lightweight
+as possible. That is achieved by prefering preprocessor metaprogramming
+to template metaprogramming. Expanding a macro is far more efficient
+than instantiating a template. In some cases, the "clean" version takes
+10x longer to compile than the "dirty" version.
+The "clean and slow" version of Proto can still be found at
+ Anyone who is interested
+can download it and verify that it is, in fact, unusably slow to compile.
+Note that this branch's development was abandoned, and it does not
+conform exactly with Proto's current interface.

Modified: trunk/libs/xpressive/proto/example/Jamfile.v2
--- trunk/libs/xpressive/proto/example/Jamfile.v2 (original)
+++ trunk/libs/xpressive/proto/example/Jamfile.v2 2008-02-01 15:30:29 EST (Fri, 01 Feb 2008)
@@ -53,3 +53,8 @@
+exe futures
+ :
+ futures.cpp
+ ;

Added: trunk/libs/xpressive/proto/example/futures.cpp
--- (empty file)
+++ trunk/libs/xpressive/proto/example/futures.cpp 2008-02-01 15:30:29 EST (Fri, 01 Feb 2008)
@@ -0,0 +1,127 @@
+//[ FutureGroup
+// Copyright 2008 Eric Niebler. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at
+// This is an example of using Proto transforms to implement
+// Howard Hinnant's future group proposal.
+#include <boost/fusion/tuple.hpp>
+#include <boost/fusion/include/as_vector.hpp>
+#include <boost/fusion/include/joint_view.hpp>
+#include <boost/fusion/include/single_view.hpp>
+#include <boost/xpressive/proto/proto.hpp>
+#include <boost/xpressive/proto/transform.hpp>
+using namespace boost;
+using namespace proto;
+template<class L,class R>
+struct pick_left
+ BOOST_MPL_ASSERT((is_same<L, R>));
+ typedef L type;
+// Define the grammar of future group expression, as well as a
+// transform to turn them into a Fusion sequence of the correct
+// type.
+struct FutureGroup
+ : or_<
+ // terminals become a single-element Fusion sequence
+ when<
+ terminal<_>
+ , fusion::single_view<_arg>(_arg)
+ >
+ // (a && b) becomes a concatenation of the sequence
+ // from 'a' and the one from 'b':
+ , when<
+ logical_and<FutureGroup, FutureGroup>
+ , fusion::joint_view<
+ add_const<FutureGroup(_left)>,
+ add_const<FutureGroup(_right)>
+ >(FutureGroup(_left), FutureGroup(_right))
+ >
+ // (a || b) becomes the sequence for 'a', so long
+ // as it is the same as the sequence for 'b'.
+ , when<
+ logical_or<FutureGroup, FutureGroup>
+ , pick_left<
+ FutureGroup(_left)
+ , FutureGroup(_right)
+ >(FutureGroup(_left))
+ >
+ >
+template<class E>
+struct future_expr;
+struct future_dom
+ : domain<generator<future_expr>, FutureGroup>
+// Expressions in the future group domain have a .get()
+// member function that (ostensibly) blocks for the futures
+// to complete and returns the results in an appropriate
+// tuple.
+template<class E>
+struct future_expr
+ : extends<E, future_expr<E>, future_dom>
+ explicit future_expr(E const &e)
+ : extends<E, future_expr<E>, future_dom>(e)
+ {}
+ typename fusion::result_of::as_vector<
+ typename boost::result_of<FutureGroup(E,int,int)>::type
+ >::type
+ get() const
+ {
+ int i = 0;
+ return fusion::as_vector(FutureGroup()(*this, i, i));
+ }
+// The future<> type has an even simpler .get()
+// member function.
+template<class T>
+struct future
+ : future_expr<typename terminal<T>::type>
+ future(T const &t = T())
+ : future_expr<typename terminal<T>::type>(
+ terminal<T>::type::make(t)
+ )
+ {}
+ T get() const
+ {
+ return proto::arg(*this);
+ }
+struct A {};
+struct B {};
+struct C {};
+int main()
+ using fusion::tuple;
+ future<A> a;
+ future<B> b;
+ future<C> c;
+ future<tuple<A,B> > ab;
+ // Verify that various future groups have the
+ // correct return types.
+ A t0 = a.get();
+ tuple<A, B, C> t1 = (a && b && c).get();
+ tuple<A, C> t2 = ((a || a) && c).get();
+ tuple<A, B, C> t3 = ((a && b || a && b) && c).get();
+ tuple<tuple<A, B>, C> t4 = (( ab || ab) && c).get();
+ return 0;

Boost-Commit list run by bdawes at, david.abrahams at, gregod at, cpdaniel at, john at