Boost logo

Boost :

Subject: Re: [boost] Design conventions; passing functors
From: Joachim Faulhaber (afojgo_at_[hidden])
Date: 2009-03-04 16:31:26


2008/12/21 David Abrahams <dave_at_[hidden]>:
>
> on Mon Dec 01 2008, "Joachim Faulhaber" <afojgo-AT-googlemail.com> wrote:
>
>> 2008/11/29 David Abrahams <dave_at_[hidden]>:
>>>
>>>>
>>> A good choice that is both forward-looking and compatible with legacy
>>> code is to implement and document move semantics support (or a
>>> swappability requirement), and pass by value unless there's no need for
>>> an eventual copy.
>>
>> looking at library code the 'eventually being copiedness' of
>> functors seems to be a pragmatical criterion for many library
>> authors on how to pass them (boost:: and even std::).
>> If functors are eventually passed to a std algorithm
>> inside the library code (or other copy intensive code), they are
>> exposed as call by value in the libraries interface. If not they
>> are often exposed as call by const reference parameters in the
>> libraries interface.
>
> Interesting.  I'm not sure I see the point, but interesting.
>
>>>
>>>> As written earlier in this thread, I would prefer to pass functors
>>>> const reference, and without additional wrappers (which is done by
>>>> other boost libraries too). I do not call std::algorithms internally.
>>>>
>>>> Please tell me, if there are strong arguments against that.
>>>
>>> Extra copies of rvalues can be expensive, and function objects are often
>>> rvalues.
>>>
>>
>> My own functor passing design head aces have disappeared by my
>> decision *not* to expose the Combine (aggregate) functors in the
>> interface of interval_map member functions at all.
>
> I'm sorry, I have no idea what I just read (and re-read) there. Could
> you rephrase?
>

Sorry for the late answer ... I obviously missed your post over Xmas :(

What I wanted to say was this:

Functors occur in my library (ITL) for the aggregation
of associated values on insertion in interval_maps
(aggregation on overlap):

And I thought about different ways to pass the
aggregating functor like:

template<class Domain, class Codomain, ...>
class interval_map{
 ...
 //(1) My current implementation is this:
 // Combinator is the aggregating functor template,
 // instantiated at compiletime
 template<template<class>class Combinator>
 interval_map& add(const value_type& value_pair)
 { /*Combinator template passed or instantiated somewhere*/ }
 ...
}

or

template<class Domain, class Codomain, ...>
class interval_map{
 //(3) Adaptable functor
 template<template<class>class Combinator>
 interval_map& add(const value_type& value_pair,
                   const Combinator<Codomain>& combine)
 { /*combine functor passed or called somewhere*/ }

All these variants have in common that the functor can
be chosen for the call of the function add.

interval_map<int,int> m;
m.add(interval_value_pair, combiner);

During the discussion I realized that the possibility of
passing the functor to every call of the add function is
*not* desirable. It provides too much flexibility that is
not needed and can lead to unnecessary errors.

To mix the aggregating functors for one interval_map m

m.add(interval_value_pair1, inplace_plus<int>());
m.add(interval_value_pair2, inplace_max<int>());

makes no sense.

So the combine functor should be constant for every
instantiation of an interval_map. (Or at least for every
object). Like the sort order is constant and can not
be changed for every call of insert.

typedef interval_map<int, int, partial_absorber, std::less, inplace_max>
   maximizer_interval_mapT;

In this case I do not have to pass the combine functor
with calls of the add member function.

maximizer_interval_mapT maximap;
...
maximap.add(make_pair(itv, x));
  // on overlap with itv compute maximum with x

see also maximize example:
http://herold-faulhaber.de/boost_itl/doc/libs/itl/doc/html/boost_itl/examples.html#boost_itl.examples.party

>> I am going to instantiate the Combine functor as template
>> parameter for the interval_map class templates only. Similar
>> to the Compare predicate in associative containers,
>> the Combine functor of interval maps is then invariant for any
>> given interval_map instance and can not change for a
>> constructed interval_map object.
>>
>> This way, I think, the interval_map's interface is more easy
>> to use correctly and harder to use incorrectly.
>
> I'm not sure what you're saying.  Are you planning to store an instance
> of the function object in the container?  That is the normal behavior of
> standard containers.
>
I thought about that but I do not like the idea to put more than the
compare order object into the container.

Sorry for the delay
Joachim


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk