Discussion
Team LiB
Previous Section Next Section

Discussion

Function objects are modeled on function pointers. Like function pointers, the convention is to pass them by value. All of the standard algorithms pass objects by value, and your algorithms should too. For example:



template<class InputIter, class Func>


Function for_each( InputIter first, InputIter last, Function f );



Therefore, function objects must be cheap to copy and monomorphic (immune to slicing, so avoid virtual functions; see Item 54). But large and/or polymorphic objects are useful, and using them is okay; just hide the size and richness using the Pimpl idiom (see Item 43), which leaves the outer class as the required cheap-to-copy monomorphic type that still accesses rich state. The outer class should:

  • Be adaptable: Inherit from unary_function or binary_function. (See below.)

  • Have a Pimpl: Store a pointer (e.g., shared_ptr) to a large/rich implementation.

  • Have the function call operator(s): Pass these through to the implementation object.

That should be all that's needed in the outer class, other than possibly providing non-default versions of construction, assignment, and/or destruction.

Function objects should be adaptable. The standard binders and adapters rely on certain typedefs, which are provided most conveniently when your function object derives from unary_function or binary_function. Instantiate unary_function or binary_function with the same types as your operator() takes and returns, except that for each non-pointer type strip off any top-level consts and &s from the type.

Avoid providing multiple operator() functions, because that makes adaptability difficult. It's usually impossible to provide the right adaptability typedefs because the same typedef would have different values for different operator() functions.

Not all function objects are predicates. Predicates are a subset of function objects. (See Item 87.)

    Team LiB
    Previous Section Next Section