blob: 2d1e10c5e99cba46ad5eb2bb11039801895537b1 [file] [log] [blame]
[/==============================================================================
Copyright (C) 2001-2010 Joel de Guzman
Copyright (C) 2001-2005 Dan Marsden
Copyright (C) 2001-2010 Thomas Heller
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
===============================================================================/]
[section Operator]
#include <boost/phoenix/operator.hpp>
This facility provides a mechanism for lazily evaluating operators.
Syntactically, a lazy operator looks and feels like an ordinary C/C++ infix,
prefix or postfix operator. The operator application looks the same. However,
unlike ordinary operators, the actual operator execution is deferred. Samples:
arg1 + arg2
1 + arg1 * arg2
1 / -arg1
arg1 < 150
We have seen the lazy operators in action (see [link phoenix.starter_kit.lazy_operators
Quick Start - Lazy Operators]). Let's go back and examine them a little bit further:
std::find_if(c.begin(), c.end(), arg1 % 2 == 1)
Through operator overloading, the expression `arg1 % 2 == 1` actually generates
an actor. This actor object is passed on to STL's `find_if` function. From
the viewpoint of STL, the expression is simply a function object expecting a
single argument of the containers value_type. For each element in `c`,
the element is passed on as an argument `arg1` to the actor (function
object). The actor checks if this is an odd value based on the expression
`arg1 % 2 == 1` where arg1 is replaced by the container's element.
Like lazy functions (see
[link phoenix.modules.function Function]), lazy operators are not immediately executed
when invoked. Instead, an actor (see [link phoenix.actor Actor])
object is created and returned to the caller. Example:
(arg1 + arg2) * arg3
does nothing more than return an actor. A second function call will evaluate
the actual operators. Example:
std::cout << ((arg1 + arg2) * arg3)(4, 5, 6);
will print out "54".
Operator expressions are lazily evaluated following four simple rules:
# A binary operator, except `->*` will be lazily evaluated when
/at least/ one of its operands is an actor object
(see [link phoenix.actor Actor]).
# Unary operators are lazily evaluated if their argument is an actor object.
# Operator `->*` is lazily evaluated if the left hand argument is an actor object.
# The result of a lazy operator is an actor object that can in turn allow the
applications of rules 1, 2 and 3.
For example, to check the following expression is lazily evaluated:
-(arg1 + 3 + 6)
# Following rule 1, `arg1 + 3` is lazily evaluated since `arg1` is an actor
(see [link phoenix.modules.core.arguments Arguments]).
# The result of this `arg1 + 3` expression is an actor object, following rule 4.
# Continuing, `arg1 + 3 + 6` is again lazily evaluated.
Rule 2.
# By rule 4 again, the result of `arg1 + 3 + 6` is an actor object.
# As `arg1 + 3 + 6` is an actor, `-(arg1 + 3 + 6)` is lazily evaluated. Rule 2.
Lazy-operator application is highly contagious. In most cases, a single `argN`
actor infects all its immediate neighbors within a group (first level or
parenthesized expression).
Note that at least one operand of any operator must be a valid actor
for lazy evaluation to take effect. To force lazy evaluation of an
ordinary expression, we can use `ref(x)`, `val(x)` or `cref(x)` to
transform an operand into a valid actor object (see [link phoenix.modules.core Core]).
For example:
1 << 3; // Immediately evaluated
val(1) << 3; // Lazily evaluated
[heading Supported operators]
[heading Unary operators]
prefix: ~, !, -, +, ++, --, & (reference), * (dereference)
postfix: ++, --
[heading Binary operators]
=, [], +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
+, -, *, /, %, &, |, ^, <<, >>
==, !=, <, >, <=, >=
&&, ||, ->*
[heading Ternary operator]
if_else(c, a, b)
The ternary operator deserves special mention. Since C++ does not allow us to
overload the conditional expression: `c ? a : b`, the if_else pseudo function is
provided for this purpose. The behavior is identical, albeit in a lazy manner.
[heading Member pointer operator]
a->*member_object_pointer
a->*member_function_pointer
The left hand side of the member pointer operator must be an actor returning a pointer
type. The right hand side of the member pointer operator may be either a pointer to member
object or pointer to member function.
If the right hand side is a member object pointer, the result is an actor which, when evaluated,
returns a reference to that member. For example:
struct A
{
int member;
};
A* a = new A;
...
(arg1->*&A::member)(a); // returns member a->member
If the right hand side is a member function pointer, the result is an actor which, when invoked, calls the specified member function. For example:
struct A
{
int func(int);
};
A* a = new A;
int i = 0;
(arg1->*&A::func)(arg2)(a, i); // returns a->func(i)
[heading Include Files]
[table
[[Operators] [File]]
[[`-`, `+`, `++`, `--`, `+=`,
`-=`, `*=`, `/=`, `%=`,
`*`, `/`, `%`] [`#include <boost/phoenix/operator/arithmetic.hpp>`]]
[[`&=`, `|=`, `^=`, `<<=`,
`>>=`, `&`, `|`, `^`, `<<`,
`>>`] [`#include <boost/phoenix/operator/bitwise.hpp>`]]
[[`==`, `!=`, `<`,
`<=`, `>`, `>=`] [`#include <boost/phoenix/operator/comparison.hpp>`]]
[[`<<`, `>>`] [`#include <boost/phoenix/operator/io.hpp>`]]
[[`!`, &&, `||`] [`#include <boost/phoenix/operator/logical.hpp>`]]
[[`&x`, `*p`, `=`, `[]`] [`#include <boost/phoenix/operator/self.hpp>`]]
[[`if_else(c, a, b)`] [`#include <boost/phoenix/operator/if_else.hpp>`]]
[[`->*`] [`#include <boost/phoenix/operator/member.hpp>`]]
]
[endsect]