Boost logo

Boost :

From: Douglas Gregor (gregod_at_[hidden])
Date: 2001-07-21 23:52:57


On Friday 20 July 2001 04:00, you wrote:
> > The final point in the "disadvantages" swayed me. I believe it would be
> > best to remove operator() completely (thereby leaving only operator()
> > const) because
> > 1) Boost.Function can be considered to be a handle or pointer to a
> > function object, so constness of Boost.Function is disjoint from
> > constness of the targetted function object.
>
> This statement made me think about an analogy to the
> iterator/const_iterator distinction in the standard library. Perhaps
> the right distinction here is function/const_function, where
> const_function is a handle to a const function object, just as a
> const_iterator is a handle to a const iterated-over object.

Perhaps. The one major difference between iterator/const_iterator and a
function/const_function is that iterators have definitive "pointed-to" types,
e.g., iterator to int and iterator to const int. The same does not quite
apply to function, because it "points to" some dynamically-chosen type that
always has an operator() const and may have an operator() as well. I think
that because of this discrepancy the decision to call const or non-const
shouldn't be up to the 'function' itself (i.e., function or const_function),
but it should be decided by the target function object. For instance, if I
have:

struct my_function_object {
  int operator()(int, int);
  int operator()(int, int) const;
};

and I want to put a my_function_object instead into a boost::function object,
I have a choice to make: should the const or non-const version of operator()
be invoked? Non-const is the default behavior, but I can easily define a
wrapper that would instead call the const version.

> This will open some different cans of worms (what conversions should be
> supplied?) but it would make the issue of stub functions go away while

The conversions may even be impossible :). Thinking about this, for instance,
with the above my_function_object class:

boost::function<int, int, int> f = my_function_object();
boost::const_function<int, int, int> fc = f;

So "f" should call my_function_object::operator() and fc should call
my_function_object::operator() const? Can't happen: f doesn't even know
my_function_object::operator() const exists, because it only references the
non-const version, so what actually happens is that fc targets a copy of f,
which targets the non-const my_function_object::operator()!

> still allowing users who need const/non-const distinctions in their
> function objects to do that. And, it would allow one to use differing
> return types in the underlying function object when that is
> appropriate, I think... There still might be surprising results at
> times, if a user makes the two operator()'s have differing semantics,
> but in that case he deserves to have to think about things hard (IMHO,
> anyway). ;)

I can personally say that having two operator()'s that differ only in cv
qualifiers is asking for trouble, unless the only difference is the
cv-qualification of the return type; and that isn't even allowed in this case
anyway.

> What do others think? Are there issues here that I've missed in my
> rather cursory thinking about the problem?
>
> George Heintzelman
> georgeh@

        Doug


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