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 

Implement Clone via a template

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





PostPosted: Wed Dec 29, 2004 8:49 am    Post subject: Implement Clone via a template Reply with quote



Is it possible to implement a Clone() function via a template?

If I have a protocol class
class PVClass {
public:
virtual PVClass* Clone(void) = 0;
};

and I want a handle class
class ImplClass : public PVClass {
public:
virtual ImplClass* Clone(void) { return new ImplClass(*this);};
}

but I do not want to rewrite the Clone function for all derived
classes so that I can hide the code in a library and by the way add
other related functions... Is there a way for me to write :
class ImplClass : public MakePVCompatible<ImplClass> {
};

I have tried the following solution but I think it is a hack and
runtime inefficient (but a dynamic cast is not really required...):
template <class T> MakePVCompatible : public PVClass {
public:
virtual PVClass* Clone(void) { return (new T(*dynamic_cast<const
T*>(this))); };
};
It does work with Visual C++ 7.1 but does not allow me to use the
return type covariance (but I am using auto_ptr which I do not
completely master so they may be the problem for the covariance).

Is there a better solution ?

Thanks in advance,

Charles

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Maxim Yegorushkin
Guest





PostPosted: Wed Dec 29, 2004 9:07 pm    Post subject: Re: Implement Clone via a template Reply with quote



On 29 Dec 2004 03:49:00 -0500, Charles-Antoine Giuliani
<apprentice_99 (AT) hotmail (DOT) com> wrote:

Quote:
Is it possible to implement a Clone() function via a template?

[]

Quote:
but I do not want to rewrite the Clone function for all derived
classes so that I can hide the code in a library and by the way add
other related functions...

[]

Quote:
Is there a better solution ?

There is.

Just implement the clone function in concrete terminal classes in a
hierarchy. Here is an example:

struct clonable
{
virtual clonable* clone() const = 0;
virtual ~clonable() {}
};

template<class base>
struct clonable_impl : base
{
// one may need to implement forward constructors here
// that forward arguments to base's constructors

// clone() expects that base has a public or protected copy ctor
clonable_impl* clone() const { return new clonable_impl(*this); }
};

struct some : clonable
{
// ...
// not concrete - does not implement clone()
};

typedef clonable_impl<some> some_impl; // concrete, terminal

struct other : some
{
// ...
// also not concrete - does not implement clone()
};

typedef clonable_impl<other> other_impl; // concrete, terminal

--
Maxim Yegorushkin

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Niels Dekker - no reply a
Guest





PostPosted: Wed Dec 29, 2004 9:07 pm    Post subject: Re: Implement Clone via a template Reply with quote



Charles-Antoine Giuliani wrote:
Quote:
Is it possible to implement a Clone() function via a template?

Did you try the CloneFactory, from the C++ library Loki? Downloadable
at http://sourceforge.net/projects/loki-lib
It is described in Chapter 8 of Modern C++ Design, by Andrei
Alexandrescu. See also http://www.moderncppdesign.com


Quote:
If I have a protocol class
class PVClass {
public:
virtual PVClass* Clone(void) = 0;
};

and I want a handle class
class ImplClass : public PVClass {
public:
virtual ImplClass* Clone(void) { return new ImplClass(*this);};
}

Loki's CloneFactory allows you to clone your object by calling its
CreateObject member function, typically as follows:

void YourFunc(const PVClass* Original) {
PVClass* YourClone = TheFactory.CreateObject(Original);
//...
}

You'd have to do some preparation, as follows:

#include <loki/Factory.h>
Loki::CloneFactory<PVClass> TheFactory;

// The clone functions, assuming your derived classes are called
// CloneImpl_1, CloneImpl_2, and CloneImpl_3.

ImplClass_1 * CloneImpl_1(const ImplClass_1 * p) {
return new ImplClass_1(*p);
}

ImplClass_2 * CloneImpl_2(const ImplClass_2 * p) {
return new ImplClass_2(*p);
}

ImplClass_3 * CloneImpl_3(const ImplClass_3 * p) {
return new ImplClass_3(*p);
}

int main(void) {
// Register each derived class:
TheFactory.Register(typeid(ImplClass_1),
(PVClass * (*)(const PVClass *)) CloneImpl_1);
TheFactory.Register(typeid(ImplClass_2),
(PVClass * (*)(const PVClass *)) CloneImpl_2);
TheFactory.Register(typeid(ImplClass_3),
(PVClass * (*)(const PVClass *)) CloneImpl_3);

// Use TheFactory.CreateObject from here...

return 0;
}


Hope this helps,

Niels Dekker
http://www.xs4all.nl/~nd/dekkerware

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Stefan de Bruijn
Guest





PostPosted: Wed Dec 29, 2004 9:08 pm    Post subject: Re: Implement Clone via a template Reply with quote

Charles-Antoine Giuliani wrote:
Quote:
Is it possible to implement a Clone() function via a template?

Hmm...

Indeed the first thing that pops to mind is:

struct clonable {
virtual clonable* clone() const = 0;
};

template <class C>
struct cloning_impl : public clonable {
virtual clonable* clone() const { return new C(*this); }
virtual ~cloning_impl() {}
};

struct my_class : public cloning_impl<my_class> {};

The trick here is using the fact that a class C has a copy constructor,
which only takes const C& as a parameter. In this case this means *this
is taken. For extra safety one could imagine introducing a dynamic cast
like the way you did; I would just call the programmer "broken" if it
messes up this one.

There is of course another possibility. Imagine templating the my_class
itself:

typedef my_clonable_class = cloning_impl<my_class>;

template <class C>
struct cloning_impl : public clonable, public C {
virtual clonable* clone() const { return new cloning_impl(*this); }
virtual ~cloning_impl() {}
};

Greetings,

Stefan de Bruijn.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Maxim Yegorushkin
Guest





PostPosted: Thu Dec 30, 2004 3:13 am    Post subject: Re: Implement Clone via a template Reply with quote

Stefan de Bruijn wrote:

Quote:
Charles-Antoine Giuliani wrote:
Is it possible to implement a Clone() function via a template?

Hmm...

Indeed the first thing that pops to mind is:

struct clonable {
virtual clonable* clone() const = 0;
};

template <class C
struct cloning_impl : public clonable {
virtual clonable* clone() const { return new C(*this); }

Probably you meant here:
virtual clonable* clone() const { return new
C(static_cast
Quote:
virtual ~cloning_impl() {}
};

struct my_class : public cloning_impl<my_class> {};

The trick here is using the fact that a class C has a copy constructor,
which only takes const C& as a parameter. In this case this means *this
is taken. For extra safety one could imagine introducing a dynamic cast
like the way you did; I would just call the programmer "broken" if it
messes up this one.

There is of course another possibility. Imagine templating the my_class
itself:

typedef my_clonable_class = cloning_impl<my_class>;

template <class C
struct cloning_impl : public clonable, public C {
virtual clonable* clone() const { return new cloning_impl(*this); }
virtual ~cloning_impl() {}
};

The drawback, that makes this solution practically useless, is the fact
that it does not work with hierarchies.

struct clonable {...};

template struct cloning_impl {...};

struct my_class
: public cloning_impl<my_class> {...};
struct my_other_class
: public my_class {...}; // oops, clones my_class part only

--
Maxim Yegorushkin

[ 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: Thu Dec 30, 2004 3:15 am    Post subject: Re: Implement Clone via a template Reply with quote

Charles-Antoine Giuliani wrote:
Quote:
Is it possible to implement a Clone() function via a template?

If I have a protocol class
class PVClass {
public:
virtual PVClass* Clone(void) = 0;
};
[snip]
Is there a way for me to write :
class ImplClass : public MakePVCompatible<ImplClass> {
};

I have tried the following solution but I think it is a hack and
runtime inefficient (but a dynamic cast is not really required...):

static_cast should suffice.

Quote:
template <class T> MakePVCompatible : public PVClass {
public:
virtual PVClass* Clone(void) { return (new T(*dynamic_cast<const
T*>(this))); };
};
It does work with Visual C++ 7.1 but does not allow me to use the
return type covariance (but I am using auto_ptr which I do not
completely master so they may be the problem for the covariance).

Is there a better solution ?

Your solution forbids a longer hierarchy. May be you should
try

template <typename Derived,typename Base>
class AutoClone : public Base{
public:
virtual Derived* Clone() const {
return new Derived(*static_cast<Derived*>(this));
}
};

class PVCompatible : public AutoClone<PVCompatible,PVClass>{
// ...
};

Note that this is only suitable for single inheritance
unless you write an AutoClone2 (3, ...) or specialize
AutoClone for a type-list.

I would suggest not to use smart pointers as a return
value from Clone(). Anyone who calls Clone() should be aware
of the necessity to handle the ownership of the new object.

If you want to use a smart pointer for covariant returns
anyway, you'll need to write one with the base-derived
relation between the smart pointers. Something like

template <typename T,typename BasePtr>
class hierarchy_ptr: public BasePtr{
public:
typedef T element_type;
typedef BasePtr base_ptr_type;
// ...
// no data members, use casting of the top-most base's
// stored pointer (see below)
};

// specialize for BasePtr=void
template <typename T>
class hierarchy_ptr<T,void>{
public:
typedef T element_type;
typedef void base_ptr_type;
// ...
// only this specialization shall hold the pointer
private:
T* ptr_;
};

and the AutoClone will look like

template <typename Derived,typename Base>
class AutoClone : public Base{
public:
typedef hierarchy_ptr<Derived,typename Base::pointer> pointer;
virtual pointer Clone() const {
return pointer(new Derived(*static_cast<Derived*>(this)));
}
};

Finaly, class PVClass will need
typedef hierarchy_ptr<PVClass,void> pointer;

I'll rather not think what should be done to make it work
with multiple inheritance (virtual bases?). This design is
already too complicated.

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
DEX
Guest





PostPosted: Thu Dec 30, 2004 3:16 am    Post subject: Re: Implement Clone via a template Reply with quote

Solution One:
template< typename T >
class PVClass {
public:
virtual T* Clone(void) = 0;
};

template < typename T>
class ImplClass : public PVClass< T> {
public:
ImplClass(){}
virtual T* Clone(void)
{
T *i = dynamic_cast<T*>(this);
if( NULL == i ) return NULL;
return new T(*i);
}
};

class MyFirst : public ImplClass <MyFirst>
{
public:
};

class MySecond : public ImplClass <MySecond>
{
public:
};

Solution Two:
class PVClass {
public:
virtual PVClass* Clone(void) = 0;
};

template < typename T>
class ImplClass : public PVClass {
public:
ImplClass(){}
virtual PVClass* Clone(void)
{
T *i = dynamic_cast<T*>(this);
if( NULL == i ) return NULL;
return new T(*i);
}
};

class MyFirst : public ImplClass <MyFirst>
{
public:
};

class MySecond : public ImplClass <MySecond>
{
public:
};




[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Stefan de Bruijn
Guest





PostPosted: Mon Jan 03, 2005 12:48 am    Post subject: Re: Implement Clone via a template Reply with quote


Quote:
[...]
Probably you meant here:
virtual clonable* clone() const { return new
C(static_cast<C&>(*this)); }

You are so right.

Quote:
There is of course another possibility. Imagine templating the my_class
itself:

typedef my_clonable_class = cloning_impl<my_class>;

template <class C
struct cloning_impl : public clonable, public C {
virtual clonable* clone() const { return new cloning_impl(*this); }
virtual ~cloning_impl() {}
};


The drawback, that makes this solution practically useless, is the fact
that it does not work with hierarchies.

struct clonable {...};

template struct cloning_impl {...};

struct my_class
: public cloning_impl

Ehm... Inheriting yourself?

Quote:
struct my_other_class
: public my_class {...}; // oops, clones my_class part only

Yes so? It's never intended to be used like that.

struct my_class { ... };
typedef my_clonable_class = cloning_impl<my_class>;

struct my_other_class : public my_class { ... };
typedef my_clonable_other_class = cloning_impl<my_other_class>;

rather than:

struct my_other_class : public cloning_impl<my_class> { ... };
typedef my_clonable_other_class = cloning_impl<my_other_class>;

I don't really see the major drawbacks here. You can clone both - and
both belong to the great clonable family.

Greetings,

Stefan.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Maxim Yegorushkin
Guest





PostPosted: Mon Jan 03, 2005 11:16 pm    Post subject: Re: Implement Clone via a template Reply with quote

Stefan de Bruijn wrote:

Your post had two solutions, I'll comment on both.

[]

The second solution was:

Quote:
There is of course another possibility. Imagine templating the my_class
itself:

typedef my_clonable_class = cloning_impl<my_class>;

template <class C
struct cloning_impl : public clonable, public C {
virtual clonable* clone() const { return new cloning_impl(*this); }
virtual ~cloning_impl() {}
};

The above won't work for the OP.

The original question has an interface clonable and its implementation.
Here is the implementation class my_class, which *has to derive clonable
interface* in order to implement its functions (except clone()). And here
is also cloning_impl, which derives both my_class and the interface. Thus,
you end up with cloning_impl deriving the interface twice. cloning_impl
implements clone() for both derived interfaces and it happens to work when
the interface has the only function clone(). If the interface had more
pure virtual functions, cloning_impl would have to implement them all.

The first solution was:

Quote:
template struct cloning_impl : public clonable {
virtual clonable* clone() const { return new C(*this); }
virtual ~cloning_impl() {}
};

struct my_class : public cloning_impl

And I commented on it:

Quote:
The drawback, that makes this solution practically useless, is the fact
that it does not work with hierarchies.

struct clonable {...};

template <class C
struct cloning_impl {...};

struct my_class
: public cloning_impl
Ehm... Inheriting yourself?

struct my_other_class
: public my_class {...}; // oops, clones my_class part only

Commenting it, I was referring to your first solution.

Quote:
Yes so? It's never intended to be used like that.

struct my_class { ... };
typedef my_clonable_class = cloning_impl<my_class>;

struct my_other_class : public my_class { ... };
typedef my_clonable_other_class = cloning_impl<my_other_class>;

rather than:

struct my_other_class : public cloning_impl<my_class> { ... };
typedef my_clonable_other_class = cloning_impl<my_other_class>;

I don't really see the major drawbacks here. You can clone both - and
both belong to the great clonable family.

Here you probably refer to your second solution.

--
Maxim Yegorushkin

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Stefan Strasser
Guest





PostPosted: Tue Jan 04, 2005 9:35 am    Post subject: Re: Implement Clone via a template Reply with quote

Vladimir Marko schrieb:

Quote:
template <typename Derived,typename Base
class AutoClone : public Base{
public:
virtual Derived* Clone() const {
return new Derived(*static_cast }
};

class PVCompatible : public AutoClone<PVCompatible,PVClass>{
// ...
};

Note that this is only suitable for single inheritance
unless you write an AutoClone2 (3, ...) or specialize
AutoClone for a type-list.


even if you do this you will have problems with multiple heritance with
it, because AutoClone inherits the 2(or more) base classes, not
PVCompatible.
so if both your base classes provide the same virtual function you're
not able to provide a final overrider in PVCompatible.
compiler requires it to be in AutoClone.

anyone has a solution to this one?

--
Stefan

[ 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: Tue Jan 04, 2005 6:32 pm    Post subject: Re: Implement Clone via a template Reply with quote


Stefan Strasser wrote:
Quote:
Vladimir Marko schrieb:

template <typename Derived,typename Base
class AutoClone : public Base{
public:
virtual Derived* Clone() const {
return new Derived(*static_cast }
};

class PVCompatible : public AutoClone<PVCompatible,PVClass>{
// ...
};

Note that this is only suitable for single inheritance
unless you write an AutoClone2 (3, ...) or specialize
AutoClone for a type-list.


even if you do this you will have problems with multiple heritance
with
it, because AutoClone inherits the 2(or more) base classes, not
PVCompatible.
so if both your base classes provide the same virtual function you're
not able to provide a final overrider in PVCompatible.
compiler requires it to be in AutoClone.

anyone has a solution to this one?

Could You explain the problem in detail? From Your response
I understand that the following should not compile

struct Base1{
virtual ~Base1() { }
virtual void foo() { }
};

struct Base2{
virtual ~Base2() { }
virtual void foo() { }
};

struct DirectlyDerived : Base1, Base2{ };

struct Derived: DirectlyDerived{
virtual void foo() { }
};

and both gcc-3.4 and Comeau C/C++ Online accept the code.
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
Stefan Strasser
Guest





PostPosted: Wed Jan 05, 2005 10:18 am    Post subject: Re: Implement Clone via a template Reply with quote

Vladimir Marko schrieb:

Quote:
even if you do this you will have problems with multiple heritance
it, because AutoClone inherits the 2(or more) base classes, not
PVCompatible.
so if both your base classes provide the same virtual function you're
not able to provide a final overrider in PVCompatible.
compiler requires it to be in AutoClone.


sorry, the problem only appears with virtual inheritance:


struct Base{
virtual void foo();
}
struct Base1 : public virtual Base{
Quote:
virtual void foo() { }
};

struct Base2 : public virtual Base{
virtual void foo() { }
};

struct DirectlyDerived : Base1, Base2{ };

struct Derived: DirectlyDerived{
virtual void foo() { }
};


I don't understand why gcc requires an overrider in DirectlyDerived,
even if it's never instantiated.
it works when you add a pure virtual foo() to DirectlyDerived,
but you can't do this of course for a clone helper template.

--
Stefan

[ 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: Thu Jan 06, 2005 11:36 pm    Post subject: Re: Implement Clone via a template Reply with quote


Stefan Strasser wrote:
Quote:
Vladimir Marko schrieb:

even if you do this you will have problems with multiple heritance
it, because AutoClone inherits the 2(or more) base classes, not
PVCompatible.
so if both your base classes provide the same virtual function
you're
not able to provide a final overrider in PVCompatible.
compiler requires it to be in AutoClone.


sorry, the problem only appears with virtual inheritance:


struct Base{
virtual void foo();
}
struct Base1 : public virtual Base{
virtual void foo() { }
};

struct Base2 : public virtual Base{
virtual void foo() { }
};

struct DirectlyDerived : Base1, Base2{ };

struct Derived: DirectlyDerived{
virtual void foo() { }
};


I don't understand why gcc requires an overrider in DirectlyDerived,
even if it's never instantiated.

Because 10.3/2 says so and the example 10.3/10 is exactly
what we have here.

Quote:
it works when you add a pure virtual foo() to DirectlyDerived,
but you can't do this of course for a clone helper template.

Well, this seems to be a serious problem. I don't know how
often one needs to derive from two base classes with a common
virtual base that override the same virtual function, but
I suspect that even std::basic_iostream might do that.
So it could be relatively common. And I can't find any fix
for the clone template to work in such a case.
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
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.