![]() |
Home | Libraries | People | FAQ | More |
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.
![]() |
Note |
---|---|
Proto's operator overloads live in the |
As a result of Proto's operator overloads, we can say:
-_1; // OK, build a unary-negate tree node _1 + 42; // OK, build a binary-plus tree node
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.
Proto also overloads operator=
, operator[]
, and operator()
, but these operators are member functions
of the expression template rather than free functions in Proto's namespace.
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, 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, _1()
,
actually creates an expression node with one child. The child is _1
itself. Likewise, the expression
_1(7)
has two
children: _1
and 7
.
Because these operators can only be defined as member functions, 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.
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< placeholder<0> >::type _1_type; _1_type const _1 = {{}}; _1_type const * p = &_1; // OK, &_1 implicitly converted