Boost logo

Boost-Commit :

From: eric_at_[hidden]
Date: 2008-07-20 18:38:34


Author: eric_niebler
Date: 2008-07-20 18:38:34 EDT (Sun, 20 Jul 2008)
New Revision: 47642
URL: http://svn.boost.org/trac/boost/changeset/47642

Log:
improvements to the users' guide
Text files modified:
   branches/proto/v4/libs/proto/doc/calculator.qbk | 89 ++----------------
   branches/proto/v4/libs/proto/doc/construction.qbk | 192 ++++++++++++++++++++++-----------------
   branches/proto/v4/libs/proto/doc/installation.qbk | 2
   branches/proto/v4/libs/proto/doc/proto.qbk | 3
   4 files changed, 124 insertions(+), 162 deletions(-)

Modified: branches/proto/v4/libs/proto/doc/calculator.qbk
==============================================================================
--- branches/proto/v4/libs/proto/doc/calculator.qbk (original)
+++ branches/proto/v4/libs/proto/doc/calculator.qbk 2008-07-20 18:38:34 EDT (Sun, 20 Jul 2008)
@@ -54,7 +54,7 @@
 No doubt you want your expression templates to actually /do/ something. One
 approach is to define an ['evaluation context]. The context is like a function
 object that associates behaviors with the node types in your expression tree.
-An example should make it clear.
+The following example should make it clear. It is explained below.
 
     struct calculator_context
       : proto::callable_context< calculator_context const >
@@ -78,48 +78,17 @@
             return this->d2_;
         }
 
- // Handle literals:
- double operator()(proto::tag::terminal, double d) const
- {
- return d;
- }
-
- // Handle addition:
- template< typename Left, typename Right >
- double operator()(proto::tag::plus, Left const &left, Right const &right) const
- {
- return proto::eval(left, *this) + proto::eval(right, *this);
- }
-
- // Handle subtraction:
- template< typename Left, typename Right >
- double operator()(proto::tag::minus, Left const &left, Right const &right) const
- {
- return proto::eval(left, *this) - proto::eval(right, *this);
- }
-
- // Handle multiplication:
- template< typename Left, typename Right >
- double operator()(proto::tag::multiplies, Left const &left, Right const &right) const
- {
- return proto::eval(left, *this) * proto::eval(right, *this);
- }
-
- // Handle division:
- template< typename Left, typename Right >
- double operator()(proto::tag::divides, Left const &left, Right const &right) const
- {
- return proto::eval(left, *this) / proto::eval(right, *this);
- }
-
     private:
         double d1_, d2_;
     };
 
-Notice how the binary arithmetic operations are handled. First the left and
-right operands are evaluated by invoking `proto::eval()`. After the left and
-right children are evaluated, the results are combined using the appropriate
-arithmetic operation.
+In `calculator_context`, 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
+_typeof_ library to compute return types.
 
 Now that we have an evaluation context for our calculator, we can use it to
 evaluate our arithmetic expressions, as below:
@@ -133,44 +102,8 @@
     // This prints "10"
     std::cout << d << std::endl;
 
-[heading Default Expression Evaluation]
-
-You might notice that the `calculator_context` has a lot of boilerplate. It
-is fairly common for addition nodes to be handled by evaluating the left and
-right children and then adding the result, for instance. For this purpose,
-Boost.Proto provides the _default_context_, which gives the operators their usual
-meanings, and uses Boost.Typeof to deduce return types. In fact, the
-_callable_context_ from which our `calculator_context` inherits uses
-_default_context_ as a fall-back for any expression types you don't handle
-explicitly. We can use that fact to simplify our `calculator_context`
-considerably:
-
- struct calculator_context
- : proto::callable_context< calculator_context const >
- {
- calculator_context(double d1, double d2)
- : d1_(d1), d2_(d2)
- {}
-
- // Define the result type of the calculator.
- // (This makes the the calculator_context "callable".)
- typedef double result_type;
-
- // Handle the placeholders:
- double operator()(proto::tag::terminal, placeholder1) const
- {
- return this->d1_;
- }
-
- double operator()(proto::tag::terminal, placeholder2) const
- {
- return this->d2_;
- }
-
- private:
- double d1_, d2_;
- };
-
-That's pretty simple!
+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.
 
 [endsect]

Modified: branches/proto/v4/libs/proto/doc/construction.qbk
==============================================================================
--- branches/proto/v4/libs/proto/doc/construction.qbk (original)
+++ branches/proto/v4/libs/proto/doc/construction.qbk 2008-07-20 18:38:34 EDT (Sun, 20 Jul 2008)
@@ -21,11 +21,11 @@
     struct placeholder1 {};
 
     // Define the Proto-ified placeholder terminal
- terminal< placeholder1 >::type const _1 = {{}};
+ proto::terminal< placeholder1 >::type const _1 = {{}};
 
 The actual type of `_1` looks like this:
 
- expr< tag::terminal, term< placeholder1 >, 0 >
+ proto::expr< proto::tag::terminal, proto::term< placeholder1 >, 0 >
 
 The _expr_ 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
@@ -59,20 +59,23 @@
 is of type `placeholder1`. Note that we use braces to initialize `_1.child0`
 because `placeholder1` is also an aggregate.
 
-[/====================================================]
-[section:operator_overloads Proto's Operator Overloads]
-[/====================================================]
+[/=================================]
+[heading Proto's Operator Overloads]
+[/=================================]
 
 Once we have some Proto terminals, expressions involving those terminals build
-expression trees for us, as if by magic. It's not magic; Proto defines
-overloads for each of C++'s overloadable operators to make it happen. As long
+expression trees for us. Proto defines overloads for each of C++'s overloadable
+operators in the `boost::proto` namespace. As long
 as one operand is a Proto expression, the result of the operation is a tree
 node representing that operation.[footnote There are a couple of exceptions to
-this. In ["`int x; x = _1`], the assignment isn't a Proto expression, even
-though the right hand operand /is/ a Proto expression. That's just how C++ works.
+this rule. In ["`int x; x = _1`], the assignment isn't a Proto expression, even
+though the right hand operand /is/ a Proto expression. That is because in C++,
+the assignment operator must be a member function.
 The same is also true for the subscript operator and the function call
-operator, as in ["`int *x; x[_1];`] and ["`std::sin(_1);`]. Them's the breaks,
-as they say.]
+operator, as in ["`int *x; x[_1];`] and ["`std::sin(_1);`]. C++ also has special
+rules for overloads of `operator->` that make it useless for
+building expression templates, so Proto does not overload it. It does, however,
+overload `operator->*`.]
 
 [note The _expr_ struct lives in the `boost::proto` namespace, as do all of
 Proto's operator overloads. The overloads are found via ADL (Argument-Dependent
@@ -84,52 +87,61 @@
     -_1; // OK, build a unary-negate tree node
     _1 + 42; // OK, build a binary-plus tree node
 
-[endsect]
-
-[/=================================================]
-[section:expression_trees Building Expression Trees]
-[/=================================================]
+[/================================]
+[heading Building Expression Trees]
+[/================================]
 
 The `_1` node is an _expr_ type, and new nodes created with this type are
-also _expr_ types. They look like this:
+also _expr_ types. 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:
 
- // decltype( -_1 )
- proto::expr<
- proto::tag::negate
- , proto::list1<
- proto::expr<
- proto::tag::terminal
- , proto::term< placeholder1 >
- , 0
- > const &
+ // The type of the expression -_1
+ typedef
+ proto::expr<
+ proto::tag::negate
+ , proto::list1<
+ proto::expr<
+ proto::tag::terminal
+ , proto::term< placeholder1 >
+ , 0
+ > const &
+ >
+ , 1
>
- , 1
- >
+ negate_placeholder_type;
+
+ negate_placeholder_type x = -_1;
 
- // decltype( _1 + 42 )
- proto::expr<
- proto::tag::plus
- , proto::list2<
- proto::expr<
- proto::tag::terminal
- , proto::term< placeholder1 >
- , 0
- > const &
- , proto::expr<
- proto::tag::terminal
- , proto::term< int const & >
- , 0
+ // The type of the expression _1 + 42
+ typedef
+ proto::expr<
+ proto::tag::plus
+ , proto::list2<
+ proto::expr<
+ proto::tag::terminal
+ , proto::term< placeholder1 >
+ , 0
+ > const &
+ , proto::expr<
+ proto::tag::terminal
+ , proto::term< int const & >
+ , 0
+ >
>
+ , 2
>
- , 2
- >
+ placeholder_plus_int_type;
+
+ placeholder_plus_int_type y = _1 + 42;
 
 There are a few things to note about these types:
 
 # Terminals have arity 0, unary expressions have arity 1 and binary expressions
   have arity 2.
 # When one Proto expression is made a child node of another Proto expression,
- it is held by reference, ['even if they are temporary objects]. This last
+ it is held by reference, ['even if it is a temporary object]. This last
   point becomes important later.
 # Non-Proto expressions, such as the integer literal, are turned into Proto
   expressions by making them Proto terminals. These terminal expressions
@@ -141,21 +153,23 @@
 reference. That means that building an expression tree is exceptionally cheap.
 It involves no copying at all.
 
-[note 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.]
-
-[endsect]
-
-[/==============================================]
-[section:left_right_arg Accessing Children Nodes]
-[/==============================================]
+[note An astute reader will notice that the object `y` 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.]
+
+[/=============================================]
+[section:left_right_child Accessing Child Nodes]
+[/=============================================]
 
 After assembling an expression into a tree, you'll naturally want to be
-able to do the reverse, and access its children.
-You may even want to be able to iterate over the children with algorithms
-from the Boost.Fusion library. This section shows how.
+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.
 
 [heading [^tag_of<>]]
 
@@ -177,7 +191,9 @@
     // Addition nodes have the "plus" tag type:
     proto::tag::plus plus_tag = get_tag_of( i + 2 );
 
+[/===================]
 [heading [^child_c()]]
+[/===================]
 
 Each node in an expression tree corresponds to an operator in an expression,
 and the children correspond to the operands, or arguments of the operator.
@@ -193,12 +209,13 @@
     assert( &i == &ri );
 
 You can use the `result_of::child_c<>` metafunction to get the type of the Nth
-child of an expression node. The nested `::type` of the `child_c<>` metafunction
-gives you the type after references and cv-qualifiers have been stripped from
-the child's type.
+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 `Expr`, you get the child's type after references and
+cv-qualifiers have been stripped from it.
 
     template<typename Expr>
- void test_result_of_arg_c(Expr const &expr)
+ void test_result_of_child_c(Expr const &expr)
     {
         typedef typename proto::result_of::child_c<Expr, 0>::type type;
 
@@ -208,29 +225,34 @@
 
     // ...
     terminal<int>::type i = {0};
- test_result_of_arg_c( i + 2 );
+ test_result_of_child_c( i + 2 );
 
-Why does the `child_c<>` metafunction strip cv-qualifiers and references? The
-reason is one of practicality. Because expression trees are most typically
-built by holding references to temporary objects, lifetime management of these
-child nodes can be problematic. If `child_c<>::type` were a reference, it
-would be very simple to create dangling references. Avoiding dangling
-references results in tedious and verbose applications of `remove_reference<>`
-and `remove_const<>`. This is especially problematic when building transforms
-that operate on ephemeral constelations of temporary objects. The current
-behavior of the `child_c<>` metafunction makes it much simpler to write correct
-code.
-
-If you would like to know exactly the type of the Nth argument, including
-references and cv-qualifiers, you can use
-`fusion::result_of::value_at<Expr, N>::type`. This way, you can tell whether
-a child is stored by value or by reference. And if you would like to know
-the exact type that _child_c_ returns, you can use
-`fusion::result_of::at_c<Expr, N>::type`. It will always be a reference type,
-and its cv-qualification depends on the cv-qualification of `Expr` and
-whether the child is stored by reference or not.
+However, if you ask for the type of the Nth child of `Expr &` or `Expr const &`
+(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 `fusion::result_of::value_at<Expr, N>::type`. The following table summarizes
+the behavior of the `child_c<>` metafunction.
+
+[table Accessing Child Types
+ [[Metafunction Invocation][When the Child Is ...][The Result Is ...]]
+ [[`proto::result_of::child_c<Expr, N>::type`][T][T]]
+ [[][T &][T]]
+ [[][T const &][T]]
+ [[`proto::result_of::child_c<Expr &, N>::type`][T][T &]]
+ [[][T &][T &]]
+ [[][T const &][T const &]]
+ [[`proto::result_of::child_c<Expr const &, N>::type`][T][T const &]]
+ [[][T &][T &]]
+ [[][T const &][T const &]]
+ [[`fusion::result_of::value_at<Expr, N>::type`][T][T]]
+ [[][T &][T &]]
+ [[][T const &][T const &]]
+]
 
+[/========================================================]
 [heading [^value()], [^child()], [^left()], and [^right()]]
+[/========================================================]
 
 Most operators in C++ are unary or binary. For that reason, accessing the
 only operand, or the left and right operands, are very common operations. For
@@ -243,8 +265,12 @@
 
 There are also `result_of::child<>`, `result_of::left<>`, and `result_of::right<>`
 metafunctions that merely forward to their `result_of::child_c<>` counterparts.
+Likewise, there is a `result_of::value<>` metafunction that returns the type of the
+value stored in a terminal node.
 
+[/===========================================]
 [heading Expression Nodes as Fusion Sequences]
+[/===========================================]
 
 Proto expression nodes are valid Fusion random-access sequences of their
 child nodes. That means you can apply Fusion algorithms to them,
@@ -286,7 +312,9 @@
 4
 ]
 
+[/========================================]
 [heading Flattening Proto Expression Tress]
+[/========================================]
 
 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
@@ -311,7 +339,7 @@
 flattened sequence are the child nodes that do *not* have tag type `T`. This
 process is evaluated recursively. So the above can correctly be written as:
 
- terminal<int>::type const _1 = {1};
+ proto::terminal<int>::type const _1 = {1};
 
     // OK, iterate over a flattened view
     fusion::for_each(

Modified: branches/proto/v4/libs/proto/doc/installation.qbk
==============================================================================
--- branches/proto/v4/libs/proto/doc/installation.qbk (original)
+++ branches/proto/v4/libs/proto/doc/installation.qbk 2008-07-20 18:38:34 EDT (Sun, 20 Jul 2008)
@@ -20,7 +20,7 @@
 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 `#include <boost/proto/proto.hpp>`. Or, you might decide to just
-include the core of Proto (`#include <boost/proto/proto.hpp>`) and whichever
+include the core of Proto (`#include <boost/proto/core.hpp>`) and whichever
 contexts and transforms you happen to use.
 
 [heading Requirements]

Modified: branches/proto/v4/libs/proto/doc/proto.qbk
==============================================================================
--- branches/proto/v4/libs/proto/doc/proto.qbk (original)
+++ branches/proto/v4/libs/proto/doc/proto.qbk 2008-07-20 18:38:34 EDT (Sun, 20 Jul 2008)
@@ -38,7 +38,8 @@
 [def _PETE_ [@http://www.codesourcery.com/pooma/download.html PETE]]
 [def _spirit_fx_ [@http://spirit.sourceforge.net Spirit Parser Framework]]
 [def _spirit_ [@http://spirit.sourceforge.net Spirit]]
-[def _xpressive_ [@../../../libs/doc/index.html Boost.Xpressive]]
+[def _xpressive_ [@../../libs/xpressive/index.html Boost.Xpressive]]
+[def _typeof_ [@../../libs/typeof/index.html Boost.Typeof]]
 [def _expr_ [classref boost::proto::expr<Tag,Args,1> `expr<>`]]
 [def _deep_copy_ [funcref boost::proto::deep_copy `deep_copy()`]]
 [def _extends_ [classref boost::proto::extends `extends<>`]]


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk