 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
ThosRTanner Guest
|
Posted: Wed Apr 20, 2005 12:35 pm Post subject: Query on covariant return types |
|
|
In another thread, someone suggested using a curiously recurring
template to implement a clone function, like this
template <class This_Class, class Base_Class> class Cloneable : public
Base_Class
{
public:
virtual This_Class *clone() const
{
return new This_Class(*static_cast<This_Class const *>(this));
}
};
class Cloneable_Base {
public:
virtual Cloneable_Base *clone() const = 0;
};
class Cloneable_Thing : public Cloneable<Cloneable_Thing,
Cloneable_Base>
{
};
Unfortunately, once I start implementing a tree of these, I get an
error from the compiler (Sun worksop 8 and gcc 4.0.0) both of which
complain that an invalid coveriant return type is being used at the
point of definition of the clone function.
Stroustrup (C++ Programming Lang, 3rd edition, s15.6.2) says that "if
the original return type was B*, then the return type of the overriding
function may be D* provided B is a public base of D". But surely
Cloneable is a base of Cloneable_Thing, so the covariant return is
valid. What is going on, because it would be really useful to do this.
At the moment I'm either reduced to implemening clone() inside
Cloneable_Thing or putting the template class as the return type and
casting the result if I really need to.
OK, at the moment, I probably shouldn't need to as clone is only going
to be used when dealing with the base class objects, but it would be be
nicer I think if this could be done, as I could see this restriction
causing issues in other templates in the future.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Alberto Barbati Guest
|
Posted: Wed Apr 20, 2005 8:54 pm Post subject: Re: Query on covariant return types |
|
|
ThosRTanner wrote:
| Quote: | In another thread, someone suggested using a curiously recurring
template to implement a clone function, like this
template <class This_Class, class Base_Class> class Cloneable : public
Base_Class
{
public:
virtual This_Class *clone() const
{
return new This_Class(*static_cast<This_Class const *>(this));
}
};
class Cloneable_Base {
public:
virtual Cloneable_Base *clone() const = 0;
};
class Cloneable_Thing : public Cloneable<Cloneable_Thing,
Cloneable_Base
{
};
Unfortunately, once I start implementing a tree of these, I get an
error from the compiler (Sun worksop 8 and gcc 4.0.0) both of which
complain that an invalid coveriant return type is being used at the
point of definition of the clone function.
|
As I posted in that other thread, the compilers are correct, the code is
ill-formed. However, the reason I gave on that thread was not correct. I
thought about the issue and I am now convinced that this is the steps
the compiler is making when it parses the definition of Cloneable_Thing:
1) "class Cloneable_Thing :", this *declares* class Cloneable_Thing and
makes the compiler look for base classes. Cloneable_Thing is not defined
yet.
2) "public Cloneable
this template-id makes the compiler instantiate the template (§14.7.1/1)
3) because of this, the declarations of all member functions are also
*immediately* instantiated (§14.7.1/1)
4) as member function clone() would override a virtual function declared
in base class Cloneable_Base, it must have a return value which is
compatible (either Cloneable_Base* or covariant)
5) alas, *at this point* Cloneable_Thing is still an incomplete type so
the compiler cannot infer that it eventually derives from Cloneable_Base
(notice that in step 3 the member definitions are not required to be
instantiated, but this is irrelevant as the declarations alone will
trigger covariancy check)
| Quote: |
Stroustrup (C++ Programming Lang, 3rd edition, s15.6.2) says that "if
the original return type was B*, then the return type of the overriding
function may be D* provided B is a public base of D". But surely
Cloneable is a base of Cloneable_Thing, so the covariant return is
valid. What is going on, because it would be really useful to do this.
|
It's a matter of timing. Once Cloneable_Thing has been defined, it will
be clearly derived from Cloneable_Base, but the detection of covariancy
must be taken at a time where Cloneable_Thing has been declared but not
yet defined.
| Quote: |
At the moment I'm either reduced to implemening clone() inside
Cloneable_Thing or putting the template class as the return type and
casting the result if I really need to.
OK, at the moment, I probably shouldn't need to as clone is only going
to be used when dealing with the base class objects, but it would be be
nicer I think if this could be done, as I could see this restriction
causing issues in other templates in the future.
|
Unfortunately, I don't see a way to work around this. Sad as it can be,
you either renounce to covariancy or re-implement the function right in
the target class.
HTH,
Alberto
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Vladimir Marko Guest
|
Posted: Wed Apr 20, 2005 8:57 pm Post subject: Re: Query on covariant return types |
|
|
ThosRTanner wrote:
| Quote: | In another thread, someone suggested using a curiously recurring
template to implement a clone function, like this
[snip] |
The thread was "Implement Clone via a template" and that
someone was me. And until today I didn't realize the biggest
problem of this design. I get an error even for your simple
snippet so let's see why.
When the compiler sees the definition of Clonable_Thing that
is derived from
Cloneable<Cloneable_Thing, Cloneable_Base>
it instantiates this base while Cloneable_Thing is still an
incomplete type. So when it checks if the return type is
covariant it doesn't know that Cloneable_Base is a base of
Cloneable_Thing. It may seem that the compiler _could_ already
know this but this would require the notion of half-incomplete
type (an incomplete type whose bases' types are known) and I
can already see some nasty issues it would create - it's simply
not worth the effort.
The template class Cloneable works only if the Base_Class
argument doesn't contain virtual clone yet. The whole design
seems to be pretty useless then. That's a pity, it was such
a nice idea.
Regards,
Vladimir Marko
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Powered by phpBB © 2001, 2006 phpBB Group
|