Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2005-11-04 12:35:23

Joel de Guzman <joel_at_[hidden]> 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

Boost list run by bdawes at, gregod at, cpdaniel at, john at