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.