Boost logo

Boost :

From: Douglas Gregor (gregod_at_[hidden])
Date: 2004-01-21 11:19:01


On Wednesday 21 January 2004 10:27 am, Peter Dimov wrote:
> Douglas Paul Gregor wrote:
> > On Wed, 21 Jan 2004, Peter Dimov wrote:
> >> Douglas Paul Gregor wrote:
> >>> boost::bind would need to be EqualityComparable for this to work,
> >>> and
> >>> at the moment it is not. It's technically trivially to do, we need
> >>> only convince Peter :)
> >>
> >> There are some interesting corner cases.
> >>
> >> int a = 1, b = 1;
> >>
> >> int f(int x) { return x; }
> >>
> >> bind(f, a) == bind<int>(f, a); // true, false, or ill-formed?
> >
> > True, I think.
>
> The underlying question here is that whether bind() should support
> heterogeneous comparisons at all, since the types of the two bind()
> expressions are not required to match. It's either true or ill-formed, but
> which one? Ill-formed is the technically trivial thing to do, the other is
> a bit more complicated. Is the complexity needed?
[snip convincing arguments]

Okay, I'm convinced. Only bind expressions of the same type should be
comparable, so your examples #1 and #2 should both be ill-formed.

> >> bind(f, ref(a)) == bind(f, ref(b)); // true or false?
> >
> > Now _that_ is an interesting corner case.
> >
> > If we say it's "true", I think we're being true to the notion that
> > reference_wrapper really is like a reference. But, of course, it's
> > obvious to us that those two function objects won't always give the same
> > results.
>
> Indeed, and note that "true" implies that it would be ill-formed when a and
> b cannot be compared, which is rather common for ref()-passed objects
> (identity semantics, noncopyable).
>
> [...]

I'm not sure that's a bad thing...

> > Users using ref() when they should be passing a pointer beware. There
> > be dragons that way.
>
> But you can't choose one or the other at will. You are limited by the
> signature of the function object that you adapt.

Well, you can replace

  ref(x)

with

  deref(&x);

where deref does something like:

template<typename Pointer, typename Pointee = typename Pointer::element_type>
  struct do_deref
  {
    typedef Pointee& result_type;

    explicit do_deref(Pointer p) : pointer(p) {}

    result_type operator()() const { return *pointer; }

  private:
    Pointer pointer;
  };
  
  template<typename Pointer>
    do_deref<Pointer> deref(Pointer p) { return do_deref<Pointer>(p); }
  template<typename T>
    do_deref<T*, T> deref(T* p) { return do_deref<T*, T>(p); }

I view ref(x) as saying "make me a reference, not a copy", so I think it
should behave like a reference. Users should use deref() if they want to
dereference a pointer as part of a function object's evaluation.

> >> and the related question whether reference_wrapper needs operator==
> >> and if so, what are its semantics. However, ...
> >
> > Whatever we do, I do not want reference_wrapper to have its own
> > operator==.
>
> Sounds reasonable, although such an operator== doing a pointer comparison
> is the technically trivial thing to do here.

Right, but it changes the semantics of reference_wrapper<T> because the
underlying operator== can be found through implicit conversion to T&.

        Doug


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