Re: [boost] [ANN] Phoenix-2 prerelease (Functions)

Joel de Guzman <joel@boost-consulting.com> writes:
Comments, feedback very welcome!
Function
Lazy functions...
#include <boost/spirit/phoenix/function/function.hpp>
The function template class provides a mechanism for lazily ^^^^^^^^^^^^^^ class template evaluating functions. Syntactically, a lazy function looks like an ordinary C/C++ function. The function call looks familiar and feels the same as ordinary C++ functions.
Except you can't use ADL.
However, unlike ordinary functions, the actual function execution is deferred. For example here are sample factorial function calls:
Whoa, where did factorial come from?
factorial(4) factorial(arg1) factorial(arg1 * 6 / factorial(ref(i)))
These functions are automatically lazily bound
Really? Even the first one?
unlike ordinary function pointers or functor objects that need to be explicitly bound through the bind function (see Bind).
A lazy function works in conjunction with a user defined function object (as usual with a member operator()).
I'm lost. What do you mean "in conjunction with?"
Only special forms of function objects are allowed.
Even more lost! Allowed where?
This is required to enable true polymorphism
I happen to have a clue as to what you mean, but most won't. Probably anyplace you mention polymorphism in this doc, you should link to the discussion of its use in this context.
(STL style monomorphic functors and function pointers can still be used through the bind facility (see Bind)).
This special function object is expected to have a nested template class apply<T0...TN> (where N is the number of arguments of its operator()). The nested template class result should have a typedef type that reflects the return type of its operator().
I guess you might be describing the Eval concept. It's not obvious though. This section needs to be reworked for clarity.
There is a special case
Of what?
for functors that accept no arguments. Such nullary functors are only required
By what?
to define a typedef result_type that reflects the return type of its operator().
Here's an example of a simple functor that computes the factorial of a number:
I would avoid "functor" except as a parenthesized note remarking that function objects are often called functors in the C++ community. That usage of "functor" is sorta deprecated and probably never should have arisen, considering its prior use with other meanings.
struct factorial_impl { template <typename Arg> struct apply { typedef Arg type; };
template <typename Arg> Arg operator()(Arg n) const { return (n <= 0) ? 1 : n * this->operator()(n-1); } };
(See factorial.cpp)
Oh, here it is. Way too late. Or mentioned too early.
The functor is polymorphic. Its arguments and return type are not fixed to a particular type. The example above can handle any Arg type as long as it can carry out the required operations (i.e. <=, * and - ).
We can declare and instantiate a lazy factorial function this way:
function<factorial_impl> factorial;
Oh, this is the point of the section? Then why is it called "Function" set in normal type, instead of "function" set in code font?
Invoking a lazy function factorial does not immediately execute the function object factorial_impl. Instead, a composite object is created and returned to the caller. Example:
factorial(arg1)
Even in factorial(4) ?
does nothing more than return a composite. A second function call will invoke the actual factorial function. Example:
int i = 4; cout << factorial(arg1)(i);
will print out "24".
Take note that in certain cases (e.g. for function objects with state), an instance of the functor may be passed on to the constructor. Example:
function<factorial_impl> factorial(ftor);
where ftor is an instance of factorial_impl (this is not necessary ^^^^ needs antecedent in this case since factorial is a simple stateless functor). Take ^^^^ too many "this"es. Eliminate the first.
care though when using functors with state because the functors are ^^^^^^ ^ strike , held by value.
I don't think you mean that. I think you mean "Functors are often copied repeatedly, and the state may be changed in one or more copies, rather than in the original."
It is best to keep the data manipulated by a functor outside the functor itself and keep a reference to this data inside the functor. Also, it is best to keep functors as small as possible.
-- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (1)
-
David Abrahams