Topic: Overloading *_cast<>


Author: 010cv25u02@sneakemail.com (Daphne Pfister)
Date: Tue, 17 Dec 2002 19:03:00 +0000 (UTC)
Raw View
dheld@codelogicconsulting.com ("David B. Held") wrote in message news:<uusca4c1ka111c@corp.supernews.com>...
> Actually, the Boost version is a *function template*, not a class
> template. ;)  Consequently, it's much simpler (literally the three or four
> lines I showed).  Of course, that's because Peter hid most of the actual
> casting apparatus inside shared_ptr<> (which is actually a better idea,
> because each pointer type probably knows best how and where to do
> this...also, think policy-based pointers, where you might want to
> prevent dynamic casting for certain policy combinations).
Actually the sample I provided also depended on the smart pointer
classes to do the dynamic casting, the only "fancy stuff" is that I
tend to have the conversion from a smart pointer to mutable data to a
smart pointer to constant data.  (I've found that religious use of
constant vs. non-constant can yield huge runtime/stability benefits
with properly designed code (at least for the program domain that I
normally work in....) so I always add the extra machinery.)

As for using a function template, I don't see how to implement a
function template that safely and conveniently handled dynamic cast
between specializable smart pointers.

For example allowing one to go from smart_ptr<T,tag::const_tag> to a
smart_ptr<T,tag::non_const_tag>, using a syntax of:
  smart_ptr<U,tag::non_const_tag> const src(...);
  smart_ptr<T,tag::const_tag> const
   dest(my_dynamic_cast<smart_ptr<T,tag::const_tag> >(src));

Insuring that the reverse gets a compiler error:
  smart_ptr<U,tag::const_tag> const src(...);
  smart_ptr<T,tag::non_const_tag> const
   dest(my_dynamic_cast<smart_ptr<T,tag::non_const_tag> >(src));

Or even:
  related_smart_ptr<U,tag::a_tag,tag::b_tag> const src(...);
  smart_ptr<T,tag::c_tag> const
   dest(my_dynamic_cast<smart_ptr<T,tag::c_tag> >(src));

Where related_smart_ptr is a different smart pointer class with
different characteristics but can share pointers with smart_ptr...

> This has already been mentioned on Boost.  And it's a fine idea, but
> one of the issues was naming (as often occurs).  It seems to me that
> we shouldn't have to provide alternative names at all, because we are
> trying to provide a feature that raw pointers already have.  So naturally,
> user-defined overloading was the obvious choice (if it were available).
I agree here.  I like the idea of overloading dynamic cast... but am
worried about constant and breaking generic code unnecessarily.

[Bit about template parameter being smart_pointer<T> vs T deleted]
It looks like this has already been covered in other parts of this
thread.

> Actually, thinking about it a little, this way makes it harder to implement
> the user-defined cast.  I notice that you have to define a specialization
> for every configuration of your smart pointer.  The Boost implementation
> makes it fairly easy for the smart pointer itself to control the
> implementation internally.  Thus, from an implementation point of view,
> the Boost version is easier to work with.
If you have only one type of smart pointer it is fairly simple...
But suppose for a second that you have a thread aware smart pointer
using both non-exclusive read-only and exclusive read-write locking.
Let's also say that you have smart pointers that keep the object
pointed to alive and smart pointers that don't and reset if the target
object is destroyed.  I would love to be able to convert between all
of these types of smart pointers using a dynamic cast.  (I have found
a collection of different smart pointer types to be very useful in
low(kernel daemon) level RT embedded programming, which I must admit
is a niche area, especially using C++ for it.)

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dheld@codelogicconsulting.com ("David B. Held")
Date: Thu, 5 Dec 2002 23:47:55 +0000 (UTC)
Raw View
"Daniel Frey" <daniel.frey@aixigo.de> wrote in message
news:3DEF199D.11576C09@aixigo.de...
> "David B. Held" wrote:
> > [...]
> > Are you suprised when operator= does not return T&?
>
> Basically yes.

So you are of the "do literally as the ints do" camp?  But surely you are
aware of the "do the safe thing" camp?  It seems to conflict with your
philosophy regarding smart pointers.  Surely returning T const& is safer
and just as fast?

> The question is, how to write templates. If I create a function which
> has to use *_cast<T>, I know I can rely on it to return T. In other
> words: If I need a T, I know which *_cast<T> to call.

True, and in that case, you would probably want the smart pointer to
act as a drop-in substitution for a raw pointer.

> But maybe we should leave the freedom to choose the return type to
> the user,

I think this is best.

> but the example you gave has no reason (except syntactic sugar) for
> breaking breaking the general pattern (IMO).

Actually, in the example I gave, the best reason was to simply the
implementation.  But then I thought of a way to use smart_ptr<T>
instead, and don't see that as a compelling reason any more (though
I do still think the implementation with T instead of smart_ptr<T> is
more elegant).

> [...]
> It depends on what you need and use. I think that intrusive smart
> pointers are the only way to make smart pointers safe enough to use
> them for production code. I won't allow smart pointers that can be
> broken by 1 to be used for our companies projects.

Obviously, not everyone agrees with you. ;)

> I can't follow you here, sorry. Can you give some examples of what
> you mean?

void foo(iterator begin, iterator end)
{
    struct some_functor : std::unary_function<my_type>
    {
        void operator()(my_type const& v) { ... }
    };

    std::for_each(begin, end, some_functor());
}


> I also have another problem which you might try to solve by the
> same approach: Given:
>
> class A {
>   virtual A* f();
> };
>
> class B : A {
>   virtual B* f(); // OK
> };
>
> Try to replace the returned 'A*' and 'B*' with smart pointers :) Can
> we allow it given that the user defined an appropriate cast or
> something similar? This questions kept me thinking for a long time but
> I never found a solution...

Oh, you mean should we allow covariant return types that return
something other than the class in question?  That does seem like a tricky
problem.  Perhaps the compiler could be made to see if the return type
is explicitly convertible to cv T{*|&}.  Combine that with the implicit/
explicit conversion operator thread, and you might have something
useful. ;)

Dave


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: daniel.frey@aixigo.de (Daniel Frey)
Date: Fri, 6 Dec 2002 16:30:28 +0000 (UTC)
Raw View
"David B. Held" wrote:
>=20
> "Daniel Frey" <daniel.frey@aixigo.de> wrote in message
> news:3DEF199D.11576C09@aixigo.de...
> > "David B. Held" wrote:
> > > [...]
> > > Are you suprised when operator=3D does not return T&?
> >
> > Basically yes.
>=20
> So you are of the "do literally as the ints do" camp?  But surely you a=
re
> aware of the "do the safe thing" camp?  It seems to conflict with your
> philosophy regarding smart pointers.  Surely returning T const& is safe=
r
> and just as fast?

The "basically yes" relates to the next point given:

> > The question is, how to write templates. If I create a function which
> > has to use *_cast<T>, I know I can rely on it to return T. In other
> > words: If I need a T, I know which *_cast<T> to call.
>=20
> True, and in that case, you would probably want the smart pointer to
> act as a drop-in substitution for a raw pointer.
>=20
> > But maybe we should leave the freedom to choose the return type to
> > the user,
>=20
> I think this is best.
>=20
> > but the example you gave has no reason (except syntactic sugar) for
> > breaking breaking the general pattern (IMO).

"Basically yes" means, that I would be surprised if I would notice a
difference when using it in the usual ways. Operator=3D could return a
"my_funny_proxy" or whatever, as long as I can use it for "a =3D b =3D c".
If I have to write "a =3D *( b =3D c )" because you return a proxy which
needs to be dereferenced to work, I would be surprised. The same applies
to the casts: If I need a T, I use *_cast< T >. I think that C++
programmers have to learn a lot of rules already, and learning *general*
rules that apply almost everywhere is a good thing. But when you have to
learn rules only for a special case (here: a special syntax of
dynamic_cast for smart_ptr), this needs a very good reason. Saving you
some typing is IMHO not reason enough. Leaving the freedom to the user
to return whatever he wants is also a good thing (IMHO), as I agree to
Bjarne's view that programmers are adults that don't need nannyism.
Every feature can be used and misused. You just should ask for a
language change and give a misuse as an example ;)

> > [...]
> > It depends on what you need and use. I think that intrusive smart
> > pointers are the only way to make smart pointers safe enough to use
> > them for production code. I won't allow smart pointers that can be
> > broken by 1 to be used for our companies projects.
>=20
> Obviously, not everyone agrees with you. ;)

I am aware of this point :)) I never claimed that I found the holy
grail, it is just my personal view that influenced the example (1) I
gave and made me forget that other smart pointer classes don't have this
opportunity, so that for them your proposal makes more sense than for
me.

> > I can't follow you here, sorry. Can you give some examples of what
> > you mean?
>=20
> void foo(iterator begin, iterator end)
> {
>     struct some_functor : std::unary_function<my_type>
>     {
>         void operator()(my_type const& v) { ... }
>     };
>=20
>     std::for_each(begin, end, some_functor());
> }

Isn't this allowed already? I remember local types to be legal but to
have certain restrictions. No static members, etc. Or is my memory wrong
about this?

> > I also have another problem which you might try to solve by the
> > same approach: Given:
> >
> > class A {
> >   virtual A* f();
> > };
> >
> > class B : A {
> >   virtual B* f(); // OK
> > };
> >
> > Try to replace the returned 'A*' and 'B*' with smart pointers :) Can
> > we allow it given that the user defined an appropriate cast or
> > something similar? This questions kept me thinking for a long time bu=
t
> > I never found a solution...
>=20
> Oh, you mean should we allow covariant return types that return
> something other than the class in question?  That does seem like a tric=
ky
> problem.  Perhaps the compiler could be made to see if the return type
> is explicitly convertible to cv T{*|&}.  Combine that with the implicit=
/
> explicit conversion operator thread, and you might have something
> useful. ;)

I don't think it's that easy. The result-slot is provided by the caller,
to B::f()'s implementation needs to distinguish whether it should return
a smart_ptr< B > or if it has to create a temporary smart_ptr< B > that
is converted to a smart_ptr< A > (through whatever function...). Given
that caller and callee can reside in different translation unit this
seems like a very hard task to accomplish. You could add several
implementation of f() but that gives you a bag of new problems, code
bloat would be the smallest. What if a user wants to store a pointer to
the function and call it later? Which pointer to B::f() will be get? As
I said, I never found a solution to the problem. Smart pointers cannot
be used as a replacement for covariant return types, neither with
'explicit cast operators' nor with overloaded '*_cast<>'.

Regards, Daniel

--=20
Daniel Frey

aixigo AG - financial training, research and technology
Schlo=DF-Rahe-Stra=DFe 15, 52072 Aachen, Germany
fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99
eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: pdimov@mmltd.net (Peter Dimov)
Date: Fri, 6 Dec 2002 17:15:41 +0000 (UTC)
Raw View
dheld@codelogicconsulting.com ("David B. Held") wrote in message news:<uusfabe3ulr53e@corp.supernews.com>...
> "Peter Dimov" <pdimov@mmltd.net> wrote in message
> news:7dc3b1ea.0212040552.1012bc50@posting.google.com...
> > [...]
> > But note that a standard *_cast<R> always returns R.
>
> This is true, but is it necessary?  Does it help enforce invariants?  Or
> does
> the utility of user-defined overloads justify the loss of this restriction?
> Like
> before operator overloading, operator= always returned T&.  Now we
> can make it return T const&.  Different, but necessarily bad?  I guess I
> don't know.

There are two main reasons to overload an operator. First, notational
convenience: a = b is better than a.Assign(b) or assign(a, b). Second,
consistency is important for generic code. A function template is
easier to write if assignment is always spelled a = b and the return
type is consistent.

In our case, consistency would require

smart_ptr<X> p = dynamic_cast< smart_ptr<X> >(q);

but notational convenience would prefer

smart_ptr<X> p = dynamic_pointer_cast<X>(q);

which is reasonably consistent for template use.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: daniel.frey@aixigo.de (Daniel Frey)
Date: Fri, 6 Dec 2002 17:16:29 +0000 (UTC)
Raw View
Daniel Frey wrote:
>=20
> Every feature can be used and misused. You just should ask for a
> language change and give a misuse as an example ;)

Sorry, I meant: "shouldn't" instead of "should" :o)

Regards, Daniel

--=20
Daniel Frey

aixigo AG - financial training, research and technology
Schlo=DF-Rahe-Stra=DFe 15, 52072 Aachen, Germany
fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99
eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dheld@codelogicconsulting.com ("David B. Held")
Date: Fri, 6 Dec 2002 20:40:20 +0000 (UTC)
Raw View
"Peter Dimov" <pdimov@mmltd.net> wrote in message
news:7dc3b1ea.0212060615.69967cb5@posting.google.com...
> [...]
> smart_ptr<X> p = dynamic_pointer_cast<X>(q);

Originally, I thought it redundant to have to say "pointer" in the name,
since it is usually used with pointers anyway.  But in this case, it seems
to be convenient, because it's like taking the * out of the <X*> and
putting it into the cast name.

Dave


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dheld@codelogicconsulting.com ("David B. Held")
Date: Wed, 4 Dec 2002 19:30:38 +0000 (UTC)
Raw View
"Daniel Frey" <daniel.frey@aixigo.de> wrote in message
news:3DEE4213.BA5B74F0@aixigo.de...
>
> A *_cast< X > should return X, nothing else - or I'd be very
> surprised (to say it with nice words ;)

Are you suprised when operator= does not return T&?

> [...]
> Consider that you have a smart-pointer that is legal with //1.
> What would you change then? (be it language-wise or not...)

In general, 1 will not be correct for any externally counted smart
pointer.  Since these are very popular, I don't consider it realistic
to consider the case where 1 is always correct.  However, the
failure to overload the cast operators introduces non-orthogonality
(which may or may not be a good thing).  Another case where
I think non-orthogonality hampers good design is local types with
no linkage.  It would be really nice to be able to define local types
and use them as functors.  While I don't think everything should
be orthogonal for its own sake, I think if there is usefulness to
it, it should be considered.  In this case, I think it is useful, and if
were made available, there would probably be other uses found
for it.

Dave


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: daniel.frey@aixigo.de (Daniel Frey)
Date: Thu, 5 Dec 2002 18:09:52 +0000 (UTC)
Raw View
"David B. Held" wrote:
>=20
> "Daniel Frey" <daniel.frey@aixigo.de> wrote in message
> news:3DEE4213.BA5B74F0@aixigo.de...
> >
> > A *_cast< X > should return X, nothing else - or I'd be very
> > surprised (to say it with nice words ;)
>=20
> Are you suprised when operator=3D does not return T&?

Basically yes. The question is, how to write templates. If I create a
function which has to use *_cast<T>, I know I can rely on it to return
T. In other words: If I need a T, I know which *_cast<T> to call. But
maybe we should leave the freedom to choose the return type to the user,
but the example you gave has no reason (except syntactic sugar) for
breaking breaking the general pattern (IMO).

> > [...]
> > Consider that you have a smart-pointer that is legal with //1.
> > What would you change then? (be it language-wise or not...)
>=20
> In general, 1 will not be correct for any externally counted smart
> pointer.  Since these are very popular, I don't consider it realistic
> to consider the case where 1 is always correct.  However, the

It depends on what you need and use. I think that intrusive smart
pointers are the only way to make smart pointers safe enough to use them
for production code. I won't allow smart pointers that can be broken by
1 to be used for our companies projects. You can use intrusive smart
pointers with classes that don't have the counter embedded, but it
requires you to write a little bit more code (one indirection from the
users point of view). This is IMHO more acceptable than "unsafe" smart
pointers (which are usually also less efficient). But I know that your
proposal shouldn't be judged by smart pointers only :)

> failure to overload the cast operators introduces non-orthogonality
> (which may or may not be a good thing).  Another case where
> I think non-orthogonality hampers good design is local types with
> no linkage.  It would be really nice to be able to define local types
> and use them as functors.  While I don't think everything should
> be orthogonal for its own sake, I think if there is usefulness to
> it, it should be considered.  In this case, I think it is useful, and i=
f
> were made available, there would probably be other uses found
> for it.

I can't follow you here, sorry. Can you give some examples of what you
mean? I also have another problem which you might try to solve by the
same approach: Given:

class A {
  virtual A* f();
};

class B : A {
  virtual B* f(); // OK
};

Try to replace the returned 'A*' and 'B*' with smart pointers :) Can we
allow it given that the user defined an appropriate cast or something
similar? This questions kept me thinking for a long time but I never
found a solution...

Regards, Daniel

--=20
Daniel Frey

aixigo AG - financial training, research and technology
Schlo=DF-Rahe-Stra=DFe 15, 52072 Aachen, Germany
fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99
eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dheld@codelogicconsulting.com ("David B. Held")
Date: Tue, 3 Dec 2002 22:08:43 +0000 (UTC)
Raw View
I think it would be useful to be able to write user-defined overloads of
dynamic_cast<> and static_cast<>.  In particular, it would facilitate
smart pointer development.  It seems to me that this wouldn't be much
different than allowing user-defined operator new, etc.  It would be
nice to be able to write this:

template <typename T, typename U>
smart_ptr<T> dynamic_cast(smart_ptr<U> const& p)
{
    // This is essentially boost::shared_dynamic_cast<>()
    return smart_ptr<T>(p, dynamic_cast_tag());
}

This would allow usage like so:

class Base
{
public:
    virtual ~Base();
};

class Child : public Base
{
};

smart_ptr<Base> p(new Child);
smart_ptr<Child> q(dynamic_cast<Child>(p));

Unless I'm missing something, this usage doesn't even interfere with
the usual applications of dynamic_cast<>.  You should still be able to
do:

Base* r = new Child;
Child* s = dynamic_cast<Child*>(r);

I suppose that for certain unusual element types, it could look
ambiguous:

smart_ptr<Base*> t(new Child*);
smart_ptr<Child*> u(dynamic_cast<Child*>(t));

However, it should be easy for the compiler to tell this situation from
the one above, based on the type of t.  At any rate, this proposal would
not break any existing code that I can see.  However, it would help
fulfill the C++ philosophy of creating user-defined types that act just
like the intrinsics.  In this case, it's not exact, since a dynamic_cast
specifies the actual pointer type in the explicit template parameter,
whereas, the smart pointer version does not.  However, it makes the
two extremely similar, and helps avoid the necessity of creating cast
names that are confusingly similar to the intrinsics, or awkwardly long.

Dave



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: pfister@nortelnetworks.com ("Daphne Pfister")
Date: Wed, 4 Dec 2002 04:15:57 +0000 (UTC)
Raw View
As a heavy user of smart pointers I like this idea.

I guess something like it could be done currently...
template <typename T_>
class my_dynamic_cast;

template <typename T_>
class my_dynamic_cast<T_*> {
public:
  template <typename U_>
  explicit my_dynamic_cast(U_* u)
    : data_(dynamic_cast<U_*>(u))
  {}

  operator T_* const() const { return data_; }

private:
  T_* const data_;
};

template <typename T_>
class my_dynamic_cast<T_&> {
public:
  template <typename U_>
  explicit my_dynamic_cast(U_& u)
    : data_(dynamic_cast<U_&>(u))
  {}

  operator T_&() { return data_; }

private:
  T_& data_;
};

Then to override, for say smart_ptr<__, __const_tag> you could write
something like:

template <typename T_>
class my_dynamic_cast<smart_ptr<T_,tag::non_const_tag> > {
public:
  template <typename U_>
  explicit my_dynamic_cast(smart_ptr<U_,tag::non_const_tag> u)
    : data_(smart_ptr<T_,tag::non_const_tag>(u, dynamic_cast_tag()))
  {}

  operator smart_ptr<T_,tag::non_const_tag> const() const { return
data_; }

private:
  smart_ptr<T_,tag::non_const_tag> const data_;
};

template <typename T_>
class my_dynamic_cast<smart_ptr<T_,tag::const_tag> > {
public:
  template <typename U_>
  explicit my_dynamic_cast(smart_ptr<U_,tag::const_tag> u)
    : data_(smart_ptr<T_,tag::const_tag>(u, dynamic_cast_tag()))
  {}
  template <typename U_>
  explicit my_dynamic_cast(smart_ptr<U_,tag::non_const_tag> u)
    : data_(smart_ptr<T_,tag::const_tag>(u, dynamic_cast_tag()))
  {}

  operator smart_ptr<T_,tag::const_tag> const() const { return data_; }

private:
  smart_ptr<T_,tag::const_tag> const data_;
};

I wrote the above off the top of my head, so it might have some minor
errors... but I believe it should work like the proposed feature.  (I
imagine the boost stuff is similar but haven't looked into it yet.)

Though I would like to see something like this standardized so that
library writers would have a common place to put there specialized
casts.  Currently I tend to use `as_type<U>' templated member functions
in my code, as well as having certain types of my smart pointers handle
the dynamic stuff internally and throw for mismatching types.

"David B. Held" wrote:
>
> I think it would be useful to be able to write user-defined overloads of
> dynamic_cast<> and static_cast<>.  In particular, it would facilitate
> smart pointer development.  It seems to me that this wouldn't be much
> different than allowing user-defined operator new, etc.  It would be
> nice to be able to write this:
>
> template <typename T, typename U>
> smart_ptr<T> dynamic_cast(smart_ptr<U> const& p)
> {
>     // This is essentially boost::shared_dynamic_cast<>()
>     return smart_ptr<T>(p, dynamic_cast_tag());
> }
>...
> smart_ptr<Base> p(new Child);
> smart_ptr<Child> q(dynamic_cast<Child>(p));
Wouldn't:
  smart_ptr<Child> q(dynamic_cast<smart_ptr<Child> >(p));
make more sense as the syntax to invoke the code.  Especially given
templated code, where smart_ptr<Child> is likely to be a typedef.

>
> smart_ptr<Base*> t(new Child*);
> smart_ptr<Child*> u(dynamic_cast<Child*>(t));
This would mean that the way to do this would be not ambiguous:
  smart_ptr<Child*> u(dynamic_cast<smart_ptr<Child*> >(t));

Daphne

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dheld@codelogicconsulting.com ("David B. Held")
Date: Wed, 4 Dec 2002 16:50:08 +0000 (UTC)
Raw View
""Daphne Pfister"" <pfister@nortelnetworks.com> wrote in message
news:3DED80C3.B29489CB@americasm01.nt.com...
> As a heavy user of smart pointers I like this idea.
>
> I guess something like it could be done currently...
> template <typename T_>
> class my_dynamic_cast;
> [...]

Wow, that's a lot of machinery!

> I wrote the above off the top of my head, so it might have some
> minor errors... but I believe it should work like the proposed feature.
> (I imagine the boost stuff is similar but haven't looked into it yet.)

Actually, the Boost version is a *function template*, not a class
template. ;)  Consequently, it's much simpler (literally the three or four
lines I showed).  Of course, that's because Peter hid most of the actual
casting apparatus inside shared_ptr<> (which is actually a better idea,
because each pointer type probably knows best how and where to do
this...also, think policy-based pointers, where you might want to
prevent dynamic casting for certain policy combinations).

> Though I would like to see something like this standardized so that
> library writers would have a common place to put there specialized
> casts.

This has already been mentioned on Boost.  And it's a fine idea, but
one of the issues was naming (as often occurs).  It seems to me that
we shouldn't have to provide alternative names at all, because we are
trying to provide a feature that raw pointers already have.  So naturally,
user-defined overloading was the obvious choice (if it were available).

> [...]
> > smart_ptr<Base> p(new Child);
> > smart_ptr<Child> q(dynamic_cast<Child>(p));
> Wouldn't:
>   smart_ptr<Child> q(dynamic_cast<smart_ptr<Child> >(p));
> make more sense as the syntax to invoke the code.  Especially given
> templated code, where smart_ptr<Child> is likely to be a typedef.

Yes and no.  It would be more analogous to the raw pointer case.
However, there is already a precedent for not including the smart pointer
name with shared_dynamic_cast<>.  Also, we're programmers, we're
lazy, and we prefer writing the shorter version, even if a typedef exists to
make it similarly short. ;)  I would argue that the only reason you include
the pointer in a raw dynamic_cast<> is to distinguish a pointer cast from
a reference cast, which has different semantics.  Technically, that could
all be inferred from the arguments, so I'm not exactly sure why we need
to specify it at all, except possibly to make dynamic_cast<> consistent
with the other casts, which work with values as well as pointers and refs.
Since smart pointers and smart references necessarily don't work with
values, I think their form should infer the proper type.

> > smart_ptr<Base*> t(new Child*);
> > smart_ptr<Child*> u(dynamic_cast<Child*>(t));
> This would mean that the way to do this would be not ambiguous:
>   smart_ptr<Child*> u(dynamic_cast<smart_ptr<Child*> >(t));

Actually, thinking about it a little, this way makes it harder to implement
the user-defined cast.  I notice that you have to define a specialization
for
every configuration of your smart pointer.  The Boost implementation
makes it fairly easy for the smart pointer itself to control the
implementation internally.  Thus, from an implementation point of view,
the Boost version is easier to work with.

Dave


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: daniel.frey@aixigo.de (Daniel Frey)
Date: Wed, 4 Dec 2002 16:51:25 +0000 (UTC)
Raw View
"David B. Held" wrote:
>=20
> I think it would be useful to be able to write user-defined overloads o=
f
> dynamic_cast<> and static_cast<>.  In particular, it would facilitate
> smart pointer development.  It seems to me that this wouldn't be much
> different than allowing user-defined operator new, etc.  It would be
> nice to be able to write this:
>=20
> template <typename T, typename U>
> smart_ptr<T> dynamic_cast(smart_ptr<U> const& p)
> {
>     // This is essentially boost::shared_dynamic_cast<>()
>     return smart_ptr<T>(p, dynamic_cast_tag());
> }
>=20
> This would allow usage like so:

  smart_ptr< Child > q( dynamic_cast< Child >( p ) );

This is not a "natural" syntax IMHO, I would expect:

  smart_ptr< Child > q( dynamic_cast< smart_ptr< Child > >( p ) );

Which leads to the question whether it is better than:

  smart_ptr< Child > q( dynamic_cast< Child* >( p.get() ) ); // 1

or a static function of smart_ptr like this:

  smart_ptr< Child > q( smart_ptr< Child >::dynamic( p ) ); // 2

Both 1 and 2 are possible today without a language change and personally
I think 1 is the preferable solution, YMMV. Thus I don't think that this
example justifies a language change. If it comes to generic programming,
you proposal is better than 1 and 2, as it doesn't rely on a get() or
dynamic() function. Yet I would like to see another language change to
solve this problem: "explicit conversion operators". Something like:

template< typename T >
class smart_ptr {
  ...
public:
  explicit operator T*() const { return get() };
  ...
}

And than using it like this:

  smart_ptr< Child > q( dynamic_cast< Child* >( Child*( p ) ) );

without polluting the interface with an implicit conversion to T* or the
need for a "standardized" function like as< T >(). See also
http://groups.google.com/groups?hl=3Den&lr=3D&ie=3DUTF-8&selm=3D3A2D10EE.=
35544D0A%40aixigo.de
for more information on what I mean :)

Regards, Daniel

--=20
Daniel Frey

aixigo AG - financial training, research and technology
Schlo=DF-Rahe-Stra=DFe 15, 52072 Aachen, Germany
fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99
eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: pdimov@mmltd.net (Peter Dimov)
Date: Wed, 4 Dec 2002 16:54:33 +0000 (UTC)
Raw View
dheld@codelogicconsulting.com ("David B. Held") wrote in message news:<uuqa9i900bpi9b@corp.supernews.com>...
> I think it would be useful to be able to write user-defined overloads of
> dynamic_cast<> and static_cast<>.  In particular, it would facilitate
> smart pointer development.  It seems to me that this wouldn't be much
> different than allowing user-defined operator new, etc.  It would be
> nice to be able to write this:
>
> template <typename T, typename U>
> smart_ptr<T> dynamic_cast(smart_ptr<U> const& p)

[...]

But note that a standard *_cast<R> always returns R.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dheld@codelogicconsulting.com ("David B. Held")
Date: Wed, 4 Dec 2002 17:35:53 +0000 (UTC)
Raw View
"Daniel Frey" <daniel.frey@aixigo.de> wrote in message
news:3DEDC3F8.16A4483B@aixigo.de...
> This is not a "natural" syntax IMHO, I would expect:
>
>   smart_ptr< Child > q( dynamic_cast< smart_ptr< Child > >( p ) );

This makes it harder to implement, though it is closer to the builtin.

> Which leads to the question whether it is better than:
>
>   smart_ptr< Child > q( dynamic_cast< Child* >( p.get() ) ); // 1

So what is p->use_count() after this line? ;)

> or a static function of smart_ptr like this:
>
>   smart_ptr< Child > q( smart_ptr< Child >::dynamic( p ) ); // 2

I think the free function is better, even with a different name.

> Both 1 and 2 are possible today without a language change and
> personally think 1 is the preferable solution, YMMV.

I prefer correct solutions, so 1 is right out. ;)

> Thus I don't think that this example justifies a language change. If it
> comes to generic programming, you proposal is better than 1 and 2,
> as it doesn't rely on a get() or dynamic() function. Yet I would like to
> see another language change to solve this problem: "explicit conversion
> operators". Something like:
> [...]

While that might be a nice feature, it still provides an incorrect solution
for this case. ;)

Dave


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dheld@codelogicconsulting.com ("David B. Held")
Date: Wed, 4 Dec 2002 17:39:59 +0000 (UTC)
Raw View
"Peter Dimov" <pdimov@mmltd.net> wrote in message
news:7dc3b1ea.0212040552.1012bc50@posting.google.com...
> [...]
> But note that a standard *_cast<R> always returns R.

This is true, but is it necessary?  Does it help enforce invariants?  Or
does
the utility of user-defined overloads justify the loss of this restriction?
Like
before operator overloading, operator= always returned T&.  Now we
can make it return T const&.  Different, but necessarily bad?  I guess I
don't know.

Dave


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: daniel.frey@aixigo.de (Daniel Frey)
Date: Wed, 4 Dec 2002 18:04:42 +0000 (UTC)
Raw View
"David B. Held" wrote:
>=20
> "Daniel Frey" <daniel.frey@aixigo.de> wrote in message
> news:3DEDC3F8.16A4483B@aixigo.de...
> > This is not a "natural" syntax IMHO, I would expect:
> >
> >   smart_ptr< Child > q( dynamic_cast< smart_ptr< Child > >( p ) );
>=20
> This makes it harder to implement, though it is closer to the builtin.

A *_cast< X > should return X, nothing else - or I'd be very surprised
(to say it with nice words ;)

> > Which leads to the question whether it is better than:
> >
> >   smart_ptr< Child > q( dynamic_cast< Child* >( p.get() ) ); // 1
>=20
> So what is p->use_count() after this line? ;)

Hm, yeah, I was fooled by thinking too much of my own smart-pointer-lib
where the above is perfectly legal and safe - obviously this is not the
case for boost's smart pointers :( (Or is it given that you use
intrusive-object-counting?) That given we should discuss if a smart
pointer is safe *enough* for general use if the above is unsafe. At
least users might expect this to work and a smart-pointer should IMHO
make it legal or prevent it, but boost's smart-pointer is only
preventing it AFAIKS through documentation, which will - at least as far
as my experience with users goes - not prevent anything :o)

> > Thus I don't think that this example justifies a language change. If =
it
> > comes to generic programming, you proposal is better than 1 and 2,
> > as it doesn't rely on a get() or dynamic() function. Yet I would like=
 to
> > see another language change to solve this problem: "explicit conversi=
on
> > operators". Something like:
> > [...]
>=20
> While that might be a nice feature, it still provides an incorrect solu=
tion
> for this case. ;)

Consider that you have a smart-pointer that is legal with //1. What
would you change then? (be it language-wise or not...)

Regards, Daniel

--=20
Daniel Frey

aixigo AG - financial training, research and technology
Schlo=DF-Rahe-Stra=DFe 15, 52072 Aachen, Germany
fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99
eMail: daniel.frey@aixigo.de, web: http://www.aixigo.de

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: dheld@codelogicconsulting.com ("David B. Held")
Date: Wed, 4 Dec 2002 18:55:20 +0000 (UTC)
Raw View
"Peter Dimov" <pdimov@mmltd.net> wrote in message
news:7dc3b1ea.0212040552.1012bc50@posting.google.com...
> [...]
> But note that a standard *_cast<R> always returns R.

Ok, I guess this way might work:

    template <typename U, typename T>
    U dynamic_cast(smart_ptr<T> const& p)
    {
        STATIC_ASSERT(is_same(U, smart_ptr<typename U::element_type>));
        return U(p, dynamic_cast_tag());
    }

Dave


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]