$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
From: Douglas Gregor (gregod_at_[hidden])
Date: 2001-07-20 14:41:42
The question of Boost.Function's operator() and/or operator() const has 
reared its ugly head again. It was originally discussed in this thread:
http://groups.yahoo.com/group/boost/message/11482
Another dimension (using binders with Boost.Function) goes against the 
conclusion drawn in that thread. I'll recap the problem, solution, and its 
problems here:
Boost.Function is a set of function object wrappers for deferred calls. 
Should the function call operator be const, non-const, or should both be 
supplied? 
Currently, the implementation supplies both const and non-const version. The 
function object target is then invoked as const if the const version was 
used, and non-const if the non-const version was used. Benefits of this 
approach are:
        - Boost.Function objects can be dropped in without any semantic changes (see 
code snippet A, below).
        - Allows target function objects to have both const and non-const function 
call operators accessible through Boost.Function objects.
Disadvantages are:
        - const and non-const function call operators have the same return type, so 
one of the most common uses of giving both a const and a non-const operator() 
isn't possible anyway (i.e., return a reference-to-T for operator() and a 
reference-to-const T for operator() const).
        - target function objects _must_ have operator() const defined, even if it 
doesn't make sense. One user has been burned by this already (the stub const 
version was being called from a const Boost.Function object, but the stub 
routine didn't throw an exception or assert to make the problem obvious). 
        - &boost::function<...>::operator() requires an extra casetto choose const 
or non-const operator() (makes it tough to use binders with Boost.Function, 
see code snippet B).
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.
        2) It doesn't force users into creating stub routines, so users can always 
pass Boost.Function objects around as reference-to-const without worrying 
about triggering a stub.
        3) Calls to operator() don't modify the Boost.Function object, so it should 
be const.
        4) Easier to use binders, see code snippet B.
I'm very leary of making such a semantic change now that Boost.Function is 
available, but I do believe that the resulting interface is cleaner and more 
consistent. Code snippet A describes the resulting semantic inconsistency 
between using a function object directly and using the function object 
wrapped in a Boost.Function. Note that both the const and the non-const "do" 
_must_ have the same type if "F" is a Boost.Function, so the usefulness of 
having const and non-const operator() overloads is diminished already.
// Code snippet A
template<typename F>
struct some_type {
  some_type(F fin) : f(fin) {}
  int do(int x) { return f(x); }
  int do(int x) const { return f(x); }
  F f;
};
struct my_function {
  int operator(int x) { return x; }
  int operator(int x) const { return -x; }
};
some_type<my_function> st1(my_function());
some_type<boost::function<int, int> > st2(my_function());
With the current semantics of Boost.Function, st1 and st2 will have the same 
behavior. With the proposed semantic change, a call to st2::do() const will 
still call the non-const my_function::operator().
// Code snippet B
typedef boost::function<void, int> func;
std::vector<func> funcs;
std::for_each(funcs.begin(), funcs.end(), 
  std::bind2nd(std::mem_fun_ref(&func::operator()), 0));
Any comments would be appreciated. It seems that the impact of this change on 
users will be very minimal, and the benefits outweight any changes, but I 
would prefer some help in this decision.
        Doug