From: David Abrahams (dave_at_[hidden])
Date: 2005-11-04 12:35:23
Joel de Guzman <joel_at_[hidden]> writes:
> Comments, feedback very welcome!
> Lazy functions...
> #include <boost/spirit/phoenix/function/function.hpp>
> The function template class provides a mechanism for lazily
> 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(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
> for functors that accept no arguments. Such nullary functors are
> only required
> 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:
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
> 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
> 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
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk