Boost C++ Libraries of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards


Lazy Operators

You can use the usual set of operators to form expressions. Examples:

arg1 * arg1
ref(x) = arg1 + ref(z)
arg1 = arg2 + (3 * arg3)
ref(x) = arg1[arg2] // assuming arg1 is indexable and arg2 is a valid index

Note the expression: 3 * arg3. This expression is actually a short-hand equivalent to: val(3) * arg3. In most cases, like above, you can get away with it. But in some cases, you will have to explicitly wrap your values in val. Rules of thumb:

If these basic rules are not followed, the result is either an error, or is immediately evaluated. Some examples:

ref(x) = 123    // lazy
x = 123         // immediate

ref(x)[0]       // lazy
x[0]            // immediate

ref(x)[ref(i)]  // lazy
ref(x)[i]       // lazy (equivalent to ref(x)[val(i)])
x[ref(i)]       // illegal (x is not a phoenix primitive or expression)
ref(x[ref(i)])  // illegal (x is not a phoenix primitive or expression)

Why are the last two expression illegal? Although operator[] looks as much like a binary operator as operator= above it; the difference is that the former must be a member (i.e. x must have an operator[] that takes a phoenix primitive or expression as its argument). This will most likely not be the case.

Learn more about operators here.

First Practical Example

We've covered enough ground to present a real world example. We want to find the first odd number in an STL container. Normally we use a functor (function object) or a function pointer and pass that in to STL's find_if generic function:

Write a function:

is_odd(int arg1)
    return arg1 % 2 == 1;

Pass a pointer to the function to STL's find_if algorithm:

std::find_if(c.begin(), c.end(), &is_odd)

Using Phoenix, the same can be achieved directly with a one-liner:

std::find_if(c.begin(), c.end(), arg1 % 2 == 1)

The expression arg1 % 2 == 1 automagically creates a functor with the expected behavior. In FP, this unnamed function is called a lambda function. Unlike the function pointer version, which is monomorphic (expects and works only with a fixed type int argument), the Phoenix version is fully polymorphic and works with any container (of ints, of longs, of bignum, etc.) as long as its elements can handle the arg1 % 2 == 1 expression.

(See find_if.cpp)

...That's it, we're done. Well if you wish to know a little bit more, read on...