|
Boost-Commit : |
From: eric_at_[hidden]
Date: 2008-08-10 12:07:21
Author: eric_niebler
Date: 2008-08-10 12:07:20 EDT (Sun, 10 Aug 2008)
New Revision: 48060
URL: http://svn.boost.org/trac/boost/changeset/48060
Log:
more doc improvements
Text files modified:
branches/proto/v4/libs/proto/doc/construction.qbk | 288 +++++++++++++++++++++++----------------
branches/proto/v4/libs/proto/doc/evaluation.qbk | 10
branches/proto/v4/libs/proto/doc/glossary.qbk | 7
branches/proto/v4/libs/proto/doc/transforms.qbk | 77 ++++++----
4 files changed, 229 insertions(+), 153 deletions(-)
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-08-10 12:07:20 EDT (Sun, 10 Aug 2008)
@@ -35,9 +35,10 @@
The _expr_ template makes up the nodes in expression trees. The first template
parameter is the node type; in this case, `proto::tag::terminal`. That means
that `_1` is a leaf-node in the expression tree. The second template parameter
-is a list of child types. 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.
+is a list of child types, or in the case of terminals, the type of the terminal's
+value. 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.
The _expr_ struct is defined as follows:
@@ -47,7 +48,8 @@
template< typename Tag, typename Args >
struct expr< Tag, Args, 1 >
{
- typename Args::child0 child0;
+ typedef typename Args::child0 proto_child0;
+ proto_child0 child0;
// ...
};
@@ -65,21 +67,12 @@
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 `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 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);`]. 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->*`.]
+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.
[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
-Lookup). That is why expressions must be "tainted" with Proto-ness for Proto to
+Proto's operator overloads. The overloads 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.]
As a result of Proto's operator overloads, we can say:
@@ -87,15 +80,74 @@
-_1; // OK, build a unary-negate tree node
_1 + 42; // OK, build a binary-plus tree node
+[/=========================================================]
+[heading Assignment, Subscript, and Function Call Operators]
+[/=========================================================]
+
+The _expr_ type defines overloads of `operator=`, `operator[]`, and `operator()`
+as member functions. That's because these operators cannot be overloaded at
+namespace scope. Because _expr_ defines them as member functions, the following
+are valid Proto expressions:
+
+ _1 = 5; // OK, builds a binary assign tree node
+ _1[6]; // OK, builds a binary subscript tree node
+ _1(); // OK, builds a unary function tree node
+ _1(7); // OK, builds a binary function tree node
+ _1(8,9); // OK, builds a ternary function tree node
+ // ... etc.
+
+For the first two lines, assigment 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, `_1()`, actually creates an expression
+node with one child. The child is `_1` itself. Likewise, the expression `_1(7)`
+has two children: `_1` and `2`.
+
+Because these operators can only be defined as member functions of _expr_, the
+following expressions are invalid:
+
+ int i;
+ i = _1; // ERROR: cannot assign _1 to an int
+
+ int *p;
+ p[_1]; // ERROR: cannot use _1 as an index
+
+ std::sin(_1); // ERROR: cannot call std::sin() with _1
+
+Also, C++ has special rules for overloads of `operator->` that make it useless
+for building expression templates, so Proto does not overload it.
+
+[/==============================]
+[heading The Address-Of Operator]
+[/==============================]
+
+Proto overloads the address-of operator for expression types, so that the
+following code creates a new unary address-of tree node:
+
+ &_1; // OK, creates a unary address-of tree node
+
+It does /not/ return the address of the `_1` 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:
+
+ typedef
+ proto::terminal< placeholder1 >::type
+ placeholder1_type;
+
+ placeholder1_type const _1 = {{}};
+ placeholder1_type const * p = &_1; // OK, &_1 implicitly converted
+
[/================================]
[heading Building Expression Trees]
[/================================]
-The `_1` node is an _expr_ type, and new nodes created with this type are
-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:
+The `_1` node is an instantiation of _expr_, and expressions containing
+`_1` are also instantiations of _expr_. 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:
// The type of the expression -_1
typedef
@@ -336,7 +388,7 @@
can treat it as a flat sequence of terminals, however, using Proto's _flatten_
function. _flatten_ returns a view which makes a tree appear as a flat Fusion
sequence. If the top-most node has a tag type `T`, then the elements of the
-flattened sequence are the child nodes that do *not* have tag type `T`. This
+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:
proto::terminal<int>::type const _1 = {1};
@@ -361,196 +413,196 @@
[endsect]
-[/===============================================================]
-[section:tags_and_meta_functions Operator Tags and Meta-Functions]
-[/===============================================================]
+[/=============================================================]
+[section:tags_and_metafunctions Operator Tags and Metafunctions]
+[/=============================================================]
The following table lists the overloadable C++ operators, the Proto tag types
-for each, and the name of the Proto meta-function for generating the
-corresponding Proto expression nodes. The meta-functions are also usable as
+for each, and the name of the Proto metafunction for generating the
+corresponding Proto expression types. The metafunctions are also usable as
grammars for matching such nodes, as well as pass-through transforms, as
explained in later sections.
-[table Operators, Tags and Meta-Functions
+[table Operators, Tags and Metafunctions
[[Operator]
[Proto Tag]
- [Proto Meta-Function]]
+ [Proto Metafunction]]
[[unary `+`]
- [`tag::unary_plus`]
- [`unary_plus<>`]]
+ [`proto::tag::unary_plus`]
+ [`proto::unary_plus<>`]]
[[unary `-`]
- [`tag::negate`]
- [`negate<>`]]
+ [`proto::tag::negate`]
+ [`proto::negate<>`]]
[[unary `*`]
- [`tag::dereference`]
- [`dereference<>`]]
+ [`proto::tag::dereference`]
+ [`proto::dereference<>`]]
[[unary `~`]
- [`tag::complement`]
- [`complement<>`]]
+ [`proto::tag::complement`]
+ [`proto::complement<>`]]
[[unary `&`]
- [`tag::address_of`]
- [`address_of<>`]]
+ [`proto::tag::address_of`]
+ [`proto::address_of<>`]]
[[unary `!`]
- [`tag::logical_not`]
- [`logical_not<>`]]
+ [`proto::tag::logical_not`]
+ [`proto::logical_not<>`]]
[[unary prefix `++`]
- [`tag::pre_inc`]
- [`pre_inc<>`]]
+ [`proto::tag::pre_inc`]
+ [`proto::pre_inc<>`]]
[[unary prefix `--`]
- [`tag::pre_dec`]
- [`pre_dec<>`]]
+ [`proto::tag::pre_dec`]
+ [`proto::pre_dec<>`]]
[[unary postfix `++`]
- [`tag::post_inc`]
- [`post_inc<>`]]
+ [`proto::tag::post_inc`]
+ [`proto::post_inc<>`]]
[[unary postfix `--`]
- [`tag::post_dec`]
- [`post_dec<>`]]
+ [`proto::tag::post_dec`]
+ [`proto::post_dec<>`]]
[[binary `<<`]
- [`tag::shift_left`]
- [`shift_left<>`]]
+ [`proto::tag::shift_left`]
+ [`proto::shift_left<>`]]
[[binary `>>`]
- [`tag::shift_right`]
- [`shift_right<>`]]
+ [`proto::tag::shift_right`]
+ [`proto::shift_right<>`]]
[[binary `*`]
- [`tag::multiplies`]
- [`multiplies<>`]]
+ [`proto::tag::multiplies`]
+ [`proto::multiplies<>`]]
[[binary `/`]
- [`tag::divides`]
- [`divides<>`]]
+ [`proto::tag::divides`]
+ [`proto::divides<>`]]
[[binary `%`]
- [`tag::modulus`]
- [`modulus<>`]]
+ [`proto::tag::modulus`]
+ [`proto::modulus<>`]]
[[binary `+`]
- [`tag::plus`]
- [`plus<>`]]
+ [`proto::tag::plus`]
+ [`proto::plus<>`]]
[[binary `-`]
- [`tag::minus`]
- [`minus<>`]]
+ [`proto::tag::minus`]
+ [`proto::minus<>`]]
[[binary `<`]
- [`tag::less`]
- [`less<>`]]
+ [`proto::tag::less`]
+ [`proto::less<>`]]
[[binary `>`]
- [`tag::greater`]
- [`greater<>`]]
+ [`proto::tag::greater`]
+ [`proto::greater<>`]]
[[binary `<=`]
- [`tag::less_equal`]
- [`less_equal<>`]]
+ [`proto::tag::less_equal`]
+ [`proto::less_equal<>`]]
[[binary `>=`]
- [`tag::greater_equal`]
- [`greater_equal<>`]]
+ [`proto::tag::greater_equal`]
+ [`proto::greater_equal<>`]]
[[binary `==`]
- [`tag::equal_to`]
- [`equal_to<>`]]
+ [`proto::tag::equal_to`]
+ [`proto::equal_to<>`]]
[[binary `!=`]
- [`tag::not_equal_to`]
- [`not_equal_to<>`]]
+ [`proto::tag::not_equal_to`]
+ [`proto::not_equal_to<>`]]
[[binary `||`]
- [`tag::logical_or`]
- [`logical_or<>`]]
+ [`proto::tag::logical_or`]
+ [`proto::logical_or<>`]]
[[binary `&&`]
- [`tag::logical_and`]
- [`logical_and<>`]]
+ [`proto::tag::logical_and`]
+ [`proto::logical_and<>`]]
[[binary `&`]
- [`tag::bitwise_and`]
- [`bitwise_and<>`]]
+ [`proto::tag::bitwise_and`]
+ [`proto::bitwise_and<>`]]
[[binary `|`]
- [`tag::bitwise_or`]
- [`bitwise_or<>`]]
+ [`proto::tag::bitwise_or`]
+ [`proto::bitwise_or<>`]]
[[binary `^`]
- [`tag::bitwise_xor`]
- [`bitwise_xor<>`]]
+ [`proto::tag::bitwise_xor`]
+ [`proto::bitwise_xor<>`]]
[[binary `,`]
- [`tag::comma`]
- [`comma<>`]]
+ [`proto::tag::comma`]
+ [`proto::comma<>`]]
[[binary `->*`]
- [`tag::mem_ptr`]
- [`mem_ptr<>`]]
+ [`proto::tag::mem_ptr`]
+ [`proto::mem_ptr<>`]]
[[binary `=`]
- [`tag::assign`]
- [`assign<>`]]
+ [`proto::tag::assign`]
+ [`proto::assign<>`]]
[[binary `<<=`]
- [`tag::shift_left_assign`]
- [`shift_left_assign<>`]]
+ [`proto::tag::shift_left_assign`]
+ [`proto::shift_left_assign<>`]]
[[binary `>>=`]
- [`tag::shift_right_assign`]
- [`shift_right_assign<>`]]
+ [`proto::tag::shift_right_assign`]
+ [`proto::shift_right_assign<>`]]
[[binary `*=`]
- [`tag::multiplies_assign`]
- [`multiplies_assign<>`]]
+ [`proto::tag::multiplies_assign`]
+ [`proto::multiplies_assign<>`]]
[[binary `/=`]
- [`tag::divides_assign`]
- [`divides_assign<>`]]
+ [`proto::tag::divides_assign`]
+ [`proto::divides_assign<>`]]
[[binary `%=`]
- [`tag::modulus_assign`]
- [`modulus_assign<>`]]
+ [`proto::tag::modulus_assign`]
+ [`proto::modulus_assign<>`]]
[[binary `+=`]
- [`tag::plus_assign`]
- [`plus_assign<>`]]
+ [`proto::tag::plus_assign`]
+ [`proto::plus_assign<>`]]
[[binary `-=`]
- [`tag::minus_assign`]
- [`minus_assign<>`]]
+ [`proto::tag::minus_assign`]
+ [`proto::minus_assign<>`]]
[[binary `&=`]
- [`tag::bitwise_and_assign`]
- [`bitwise_and_assign<>`]]
+ [`proto::tag::bitwise_and_assign`]
+ [`proto::bitwise_and_assign<>`]]
[[binary `|=`]
- [`tag::bitwise_or_assign`]
- [`bitwise_or_assign<>`]]
+ [`proto::tag::bitwise_or_assign`]
+ [`proto::bitwise_or_assign<>`]]
[[binary `^=`]
- [`tag::bitwise_xor_assign`]
- [`bitwise_xor_assign<>`]]
+ [`proto::tag::bitwise_xor_assign`]
+ [`proto::bitwise_xor_assign<>`]]
[[binary subscript]
- [`tag::subscript`]
- [`subscript<>`]]
+ [`proto::tag::subscript`]
+ [`proto::subscript<>`]]
[[ternary `?:`]
- [`tag::if_else_`]
- [`if_else_<>`]]
+ [`proto::tag::if_else_`]
+ [`proto::if_else_<>`]]
[[n-ary function call]
- [`tag::function`]
- [`function<>`]]
+ [`proto::tag::function`]
+ [`proto::function<>`]]
]
[endsect]
Modified: branches/proto/v4/libs/proto/doc/evaluation.qbk
==============================================================================
--- branches/proto/v4/libs/proto/doc/evaluation.qbk (original)
+++ branches/proto/v4/libs/proto/doc/evaluation.qbk 2008-08-10 12:07:20 EDT (Sun, 10 Aug 2008)
@@ -5,7 +5,7 @@
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
-[section:expression_evaluation Expression Evaluation: Imparting Behaviors Within A Context]
+[section:expression_evaluation Expression Evaluation: Imparting Behaviors With A Context]
Once you have constructed a Proto expression tree, either by using Proto's
operator overloads or with _make_expr_ and friends, you probably want to
@@ -124,7 +124,7 @@
// A nested eval<> class template
template<
typename Expr
- , typename Tag = typename Expr::proto_tag
+ , typename Tag = typename tag_of<Expr>::type
>
struct eval;
@@ -320,7 +320,11 @@
{
template<typename Expr>
struct eval
- : default_eval<Expr, default_context const, typename Expr::proto_tag>
+ : default_eval<
+ Expr
+ , default_context const
+ , typename tag_of<Expr>::type
+ >
{};
};
Modified: branches/proto/v4/libs/proto/doc/glossary.qbk
==============================================================================
--- branches/proto/v4/libs/proto/doc/glossary.qbk (original)
+++ branches/proto/v4/libs/proto/doc/glossary.qbk 2008-08-10 12:07:20 EDT (Sun, 10 Aug 2008)
@@ -18,13 +18,18 @@
`R` is treated as a polymorphic function object and the
arguments are treated as transforms that yield the
arguments to the function object.] ]
+ [ [domain-specific language]
+ [A programming language that targets a particular problem
+ space by providing programming idioms, abstractions and
+ constructs that match the constructs within that problem
+ space.]]
[ [expression]
[A heterogeneous tree where each node is either an
instantiation of `boost::proto::expr<>` or some type
that is an extension (via `boost::proto::extends<>`
or `BOOST_PROTO_EXTENDS()`) of such an instantiation.]]
[ [grammar]
- [A grammar is a type that describes a subset of all
+ [A grammar is a type that describes a subset of
expression types. Expressions in a domain must conform
to that domain's grammar. The `proto::matches<>`
metafunction evaluates whether an expression type matches
Modified: branches/proto/v4/libs/proto/doc/transforms.qbk
==============================================================================
--- branches/proto/v4/libs/proto/doc/transforms.qbk (original)
+++ branches/proto/v4/libs/proto/doc/transforms.qbk 2008-08-10 12:07:20 EDT (Sun, 10 Aug 2008)
@@ -256,7 +256,7 @@
[note You may have noticed that Proto types like `unary_expr<>` serve several
different but related roles. In particular, `unary_expr<>` is ...
- ... [*a meta-function]: `unary_expr<T, X>::type` is a typedef for
+ ... [*a metafunction]: `unary_expr<T, X>::type` is a typedef for
`expr<T, list1<X> >`.
... [*a grammar]: `unary_expr<U, Y>` is a simle grammar that matches
@@ -1218,7 +1218,7 @@
As a side-effect, `pass_through<>` transforms all sub-expressions held by
reference into ones held by value.
-Note that all expression generator meta-functions (Eg., `unary_plus<>`,
+Note that all expression generator metafunctions (Eg., `unary_plus<>`,
`shift_right<>`, `function<>`, `nary_expr<>`, etc.) have a pass-through
transform by default, so there is rarely any need to use the `pass_through<>`
transform explicitly.
@@ -1353,22 +1353,24 @@
[section:is_callable Making Your Transform Callable]
[/=================================================]
-Transforms are typically of the form `when< Something, R(A0,A1,...) >`. The
+Transforms are typically of the form `proto::when< Something, R(A0,A1,...) >`. The
question is whether `R` represents a function to call or an object to
-construct, and the answer determines how `when<>` evaluates the transform.
-`when<>` uses the `is_callable<>` trait to disambiguate between the two.
+construct, and the answer determines how _when_ evaluates the transform.
+_when_ uses the `proto::is_callable<>` trait to disambiguate between the two.
Proto does its best to guess whether a transform 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 specialize `is_callable<>`.
+so that you know when you need to be more explicit.
-The first thing to know is that templates are not considered callable
-by default. This is true ['even if the template inherits from
-`proto::callable`]. Consider the following erroneous callable transform:
+For most types `T`, `proto::is_callable<T>` checks for inheritence from
+`proto::callable`. However, if the type `T` is a template specialization,
+Proto assumes that it is /not/ callable ['even if the template inherits from
+`proto::callable`]. We'll see why in a minute. Consider the following erroneous
+callable transform:
// Proto can't tell this defines a
// callable transform!
template<typename T>
- struct times2 : callable
+ struct times2 : proto::callable
{
typedef T result_type;
@@ -1381,11 +1383,14 @@
// ERROR! This is not going to
// multiply the int by 2.
struct IntTimes2
- : when< terminal<int>, times2<int>(_value) >
+ : proto::when<
+ proto::terminal<int>
+ , times2<int>(proto::_value)
+ >
{};
The problem is that Proto doesn't know that `times2<int>` is a callable
-transform. Instead, it assumes it's an object transform and will try to
+transform. Instead, it assumes it is an object transform and will try to
construct a `times2<int>` object and initialize it will an `int`. That
will not compile.
@@ -1393,20 +1398,21 @@
it inherits from `proto::callable`, and that is detectable, right?
The problem is that merely asking whether some type `X<Y>` inherits from
`callable` will cause the template `X<Y>` to be instantiated. That's a
-problem for a type like `std::vector<_value(_child1)>()`, which is a valid
-(object) transform that default-constructs a particular instantiation of
-`std::vector<>`. But `std::vector<>` will not suffer to be instantiated
-with `_value(_child1)` as a template parameter! As a result, Proto has
-to assume that a type `X<Y>` represents an object transform and not
-a callable transform.]
+problem for a type like `std::vector<_value(_child1)>`. `std::vector<>`
+will not suffer to be instantiated with `_value(_child1)` as a template
+parameter. As a result, Proto has to assume that a type `X<Y>` represents
+an object transform and not a callable transform.]
There are a couple of solutions to the `times2<int>` problem. One
-solution is to wrap the transform in `call<>`. This forces Proto to
-treat `times2<int>` as callable:
+solution is to wrap the transform in `proto::call<>`. This forces Proto
+to treat `times2<int>` as callable:
// OK, calls times2<int>
struct IntTimes2
- : when< terminal<int>, call<times2<int>(_value)> >
+ : proto::when<
+ proto::terminal<int>
+ , proto::call<times2<int>(proto::_value)>
+ >
{};
This can be a bit of a pain, because we need to wrap every use of
@@ -1426,21 +1432,27 @@
// OK, times2<> is callable
struct IntTimes2
- : when< terminal<int>, times2<int>(_value) >
+ : proto::when<
+ proto::terminal<int>
+ , times2<int>(proto::_value)
+ >
{};
This is better, but still a pain because of the need to open
Proto's namespace.
You could simply make sure that the transform is not
-a template. Consider the following:
+a template specialization. Consider the following:
- // No longer a template!
+ // No longer a template specialization!
struct times2int : times2<int> {};
// OK, times2int is callable
struct IntTimes2
- : when< terminal<int>, times2int(_value) >
+ : proto::when<
+ proto::terminal<int>
+ , times2int(proto::_value)
+ >
{};
This works because now Proto can tell that `times2int` inherits
@@ -1453,8 +1465,8 @@
to `proto::callable`:
// Proto will recognize this as callable
- template<typename T, typename Dummy = proto::callable>
- struct times2 : callable
+ template<typename T, typename Callable = proto::callable>
+ struct times2 : proto::callable
{
typedef T result_type;
@@ -1466,13 +1478,16 @@
// OK, this works!
struct IntTimes2
- : when< terminal<int>, times2<int>(_value) >
+ : proto::when<
+ proto::terminal<int>
+ , times2<int>(proto::_value)
+ >
{};
Note that in addition to the extra template parameter, `times2<>`
-still inherits from `callable`. That's not necessary in this example
-but it's good style because any types derived from `times2<>` (as
-`times2int` defined above) will still be considered callable.
+still inherits from `proto::callable`. That's not necessary in this
+example but it's good style because any types derived from `times2<>`
+(as `times2int` defined above) will still be considered callable.
[endsect]
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