Boost logo

Boost :

From: Ed Brey (brey_at_[hidden])
Date: 2001-03-04 12:05:54


From: "Lois Goldthwaite" <loisg_at_[hidden]>
> Member template constructors can not be used to replace the ordinary
> copy constructor and assignment operator (12.8p2). If you don't provide
> these functions, the compiler should synthesize them for you. I don't
> know what VC does in this situation.

Oooh, how insidiously clever! I did some experimenting, and VC does
properly generate its own do-nothing copy constructor, which it then prefers
over the member template. So what I suggested would not work, even though
it does compile. I wonder if something like this - where working around a
compiler bug leads one into a subtle trap of misusing the language - could
be
behind some of the VC silent bad-code generation lore (see below for a less
speculative analysis).

After experimenting with several other workaround possibilities, I have
found one that does work, AFAICT. Here's the relevant code snippets:

template <typename T> class base {};

template<typename T> class shared_ptr: public base<T> {

    shared_ptr(const shared_ptr& r):
       px(r.px) { ++*(pn = r.pn); } // unchanged

    template <typename Y>
    shared_ptr(const base<Y>& r):
       px(static_cast<const shared_ptr<Y>&>(r).px)
       {
         ++*(pn = static_cast<const shared_ptr<Y>&>(r).pn);
       }

    // Same for assignment operator.
    // ...
};

Of course, "base" would be named something like
detail::shared_ptr_no_member_templates_base, and all this tom foolery would
only be seen by compilers with broken member templates.

From: "David Abrahams" <abrahams_at_[hidden]>
> > Should we make this change to shared_ptr, and then also imbue
> > shared_array with this functionality (Trevor's example is just as
> applicable
> > to arrays)?
>
> Careful; this might suddenly also enable the Derived->Base conversion for
> arrays, which of course we don't want. You'd have to add some additional
> BOOST_STATIC_ASSERTs, e.g. for is_same<T, const U> || is_same<T, volatile
U>
> || is_same<T, const volatile U> (since remove_cv doesn't work with VC6).

That seems reasonable, although I'm not familiar with is_same. Could you
elaborate on that? I'm also curious about remove_cv. Given a conforming
compiler, how would one use that. The application I have in mind would be
to put this in shared_array:

 template<typename Y>
    shared_array(const shared_array<remove_cv T>& r):
        px(r.px) { ++*(pn = r.pn); }

where the template parameter Y is just a dummy to force the function to be a
member template so that cannot conflict with the copy constructor (on a
conforming compiler). But I don't know how to code the remove_cv (or if
there are other problems with this approach). If this could be made to work
on a conforming compiler, then it could probably also be made to work on VC
using the above base class trick.

> > Finally, does anyone know if there are any issues with VC6
> > silently generating bad code that relate to this situation?
>
> I suggest you check the mailing list archives. It's been discussed. I'm
not
> saying I'm happy with the current resolution, though ;-).

A search for "silently member templates" brought up a dozen messages, of
which only http://groups.yahoo.com/group/boost/message/2635 mentioned a
specific failure mode, which has to do with failing to call a specialized
function. There was nothing relating to DLLs. I couldn't find anything
concrete to cause one to believe that the shared_ptr workaround won't work.
STLport's success with member templates seem to be good precedent upon which
to expect success.


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