Boost logo

Boost :

From: David B. Held (dheld_at_[hidden])
Date: 2002-10-04 15:53:53


"Schoenborn, Oliver" <Oliver.Schoenborn_at_[hidden]> wrote in message
news:35C5DD9F60FED21192B00004ACA6E6C70151C880_at_nrclonex1.imti.nrc.ca...
> [...]
> I disagree Dave. For one thing, you don't need any inheritance whatsoever
> to get implicit conversions.

Well, we were talking about "free" conversions (i.e.: conversions that don't
require a copy). At least, that's what *I* was talking about.

> [...]
> I don't see how it is true in general. If you do the raw pointer
equivalent
> of the last example, you have
>
> void baz(const foo* p)
> {
> p->bar();
> p = ...; // caught for raw pointer!
> }

No, you have:

void baz(foo const*& p)

> because you rarely pass a pointer by reference.

Unless it's a smart pointer, in which case you might be anal and pass it by
const&.

> The only time you do is when you know you will modify it. However, the
> whole point of constness is to help you avoid modifying something that
> shouldn't be modified. So when the function takes a smart_ptr by
reference,
> you know it will modify it, otherwise it would take it by const reference.

Which is exactly what I was suggesting *ought* to be done.

> So you've just eliminated a standard check of constness.

I don't see how this follows from the rest.

> Another reason not to do it is that you can now slice smart_ptr by
mistake,
> though in this particular case, there is no data in the derived smart_ptr
so
> you're probably safe, but I'd have to check what the standard says about
> that. So problem there is if you ever *have* to add data to the non-const
T
> version you're breaking a fundamental rule.

If you have to add data to non-const T, you have a very strange smart
pointer
that probably needs to be examined very closely.

> Also, (if that weren't enough already) in the full implementation there
will
> be methods of the base that you want to not have visible. Those methods
> that accept a const T, since that equates to conversion from const to
> non-const.

Deriving from ptr<T const> is a weird beast. For instance, if you declare
T* p_; in ptr<T const>, for some reason, it is not visible in ptr<T>, even
if
it is protected or public, with public inheritance! I don't get it, but
that seems
to be the way it is. Furthermore, methods of ptr<T const> seem to *not*
get inherited by ptr<T>. It seems that the only thing that *does* get
inherited
is the type itself. Explain that! If you don't believe me, try this code
under
Comeau:

template <typename T>
class ptr;

template <typename T>
class ptr<T const>
{
public:
    ptr() { }
    T const* operator->() const { return p_; }
    T* get() const { return p_; }
protected:
    ptr(ptr const&);
    T* p_;
};

template <typename T>
class ptr : public ptr<T const>
{
public:
    ptr() { }

    T* operator->() const { return p_; } // Error: p_ is undefined!
    T* foo() const { return get(); } // Identifier get is undefined!
private:
    ptr(ptr const&);
};

int main()
{
    ptr<int> p;
    p.get(); // Oddly enough, this passes
}

So I guess the T const->T is a problem after all.

> All in all, it seems to me you have no choice but to use non-public
> inheritance, and because the standard doesn't seem to allow implicit
> conversion even for such inheritance (though it should AFAICT), you are
> forced to have a method that returns a ref to the base, as in my initial
> example.

I prefer my constT<> wrapper, as it can be made to work with any
pointer, doesn't require separate typedefs for const and non-const, and
doesn't require special work at the call site.

Dave


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