C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Query on covariant return types

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
ThosRTanner
Guest





PostPosted: Wed Apr 20, 2005 12:35 pm    Post subject: Query on covariant return types Reply with 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.

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





PostPosted: Wed Apr 20, 2005 8:54 pm    Post subject: Re: Query on covariant return types Reply with quote



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





PostPosted: Wed Apr 20, 2005 8:57 pm    Post subject: Re: Query on covariant return types Reply with quote



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
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
 


Powered by phpBB © 2001, 2006 phpBB Group