vendredi 18 avril 2014

modèles - valeur de retour basée sur des modèles C++ avec une fonction virtuelle pure - Stack Overflow


I have an abstract Handle<T> class that contains references an objects of type T. I want to be able to have that class be able to be converted to Handle<U>, where U is a superclass of T. I would use inheritance, but that doesn't work here. How would I go about doing this? What are good alternatives?


Example psuedo code:


template<class T>
class Handle {
public:
virtual ~Handle () {}
virtual T & operator* () const = 0;
virtual T * operator-> () const = 0;
virtual template<class U> operator Handle<U>* () const = 0; // being lazy with dumb pointer
};

template<class T>
class ConcreteHandle : public Handle<T> {
public:
explicit template<class U> ConcreteHandle (U * obj) : obj(obj) {}
virtual ~ConcreteHandle () {}
virtual T & operator* () const {
return *obj;
}
virtual T * operator-> () const {
return obj;
}
virtual template<class U> operator Handle<U>* () {
return new ConcreteHandle<U>(obj);
}
private:
T * obj;
};



As requested, this is what I'm doing


class GcPool {
public:
virtual void gc () = 0;
virtual Handle<GcObject> * construct (GcClass clazz) = 0;
};

class CompactingPool : public GcPool {
public:
virtual void gc () { ... }
virtual Handle<GcObject> * construct (GcClass clazz) { ... }
private:
Handle<GcList<Handle<GcObject> > > rootSet; // this will grow in the CompactingPool's own pool
Handle<GcList<Handle<GcObject> > > knownHandles; // this will grow in the CompactingPool's own pool.
};

knownHandles needs to be compatable with Handle so it can be in the CompatingPool's rootSet. Same goes for rootSet. I will bootstrap these special handles so a chicken and egg problem does not occur.




virtual template<class U> operator Handle<U>* () const  =0;

Template virtual function is not allowed by the language specification.


Consider this code at ideone, and then see the compilation error:



error: templates may not be ‘virtual’





Now what can you do? One solution is this:


template<class T>
class Handle {
public:

typedef typename T::super super; //U = super, which is a superclass of T.

virtual ~Handle () {}
virtual T & operator* () const = 0;
virtual T * operator-> () const = 0;

//not a template now, but still virtual
virtual super operator Handle<super> () const = 0;
};

That is, define a typedef of the base class in the derived class, and use it in the Handle. Something like this:


struct Base {//...};

struct Derived : Base { typedef Base super; //...};

Handle<Derived> handle;



Or you can define traits, as:


struct Base {//... };

struct Derived : Base { //... };

template<typename T> struct super_traits;

struct super_traits<Derived>
{
typedef Base super;
};

template<class T>
class Handle {
public:

typedef typename super_traits<T>::super super; //note this now!

virtual ~Handle () {}
virtual T & operator* () const = 0;
virtual T * operator-> () const = 0;

//not a template now, but still virtual
virtual super operator Handle<super> () const = 0;
};

In my opinion, super_traits is a superior solution, as you're defining the traits of derived classes without editing them. Also, you can define as many typedefs as you want; say your derived class has more than one base, you may want to define many typedefs, or preferably a typelist.



I have an abstract Handle<T> class that contains references an objects of type T. I want to be able to have that class be able to be converted to Handle<U>, where U is a superclass of T. I would use inheritance, but that doesn't work here. How would I go about doing this? What are good alternatives?


Example psuedo code:


template<class T>
class Handle {
public:
virtual ~Handle () {}
virtual T & operator* () const = 0;
virtual T * operator-> () const = 0;
virtual template<class U> operator Handle<U>* () const = 0; // being lazy with dumb pointer
};

template<class T>
class ConcreteHandle : public Handle<T> {
public:
explicit template<class U> ConcreteHandle (U * obj) : obj(obj) {}
virtual ~ConcreteHandle () {}
virtual T & operator* () const {
return *obj;
}
virtual T * operator-> () const {
return obj;
}
virtual template<class U> operator Handle<U>* () {
return new ConcreteHandle<U>(obj);
}
private:
T * obj;
};



As requested, this is what I'm doing


class GcPool {
public:
virtual void gc () = 0;
virtual Handle<GcObject> * construct (GcClass clazz) = 0;
};

class CompactingPool : public GcPool {
public:
virtual void gc () { ... }
virtual Handle<GcObject> * construct (GcClass clazz) { ... }
private:
Handle<GcList<Handle<GcObject> > > rootSet; // this will grow in the CompactingPool's own pool
Handle<GcList<Handle<GcObject> > > knownHandles; // this will grow in the CompactingPool's own pool.
};

knownHandles needs to be compatable with Handle so it can be in the CompatingPool's rootSet. Same goes for rootSet. I will bootstrap these special handles so a chicken and egg problem does not occur.



virtual template<class U> operator Handle<U>* () const  =0;

Template virtual function is not allowed by the language specification.


Consider this code at ideone, and then see the compilation error:



error: templates may not be ‘virtual’





Now what can you do? One solution is this:


template<class T>
class Handle {
public:

typedef typename T::super super; //U = super, which is a superclass of T.

virtual ~Handle () {}
virtual T & operator* () const = 0;
virtual T * operator-> () const = 0;

//not a template now, but still virtual
virtual super operator Handle<super> () const = 0;
};

That is, define a typedef of the base class in the derived class, and use it in the Handle. Something like this:


struct Base {//...};

struct Derived : Base { typedef Base super; //...};

Handle<Derived> handle;



Or you can define traits, as:


struct Base {//... };

struct Derived : Base { //... };

template<typename T> struct super_traits;

struct super_traits<Derived>
{
typedef Base super;
};

template<class T>
class Handle {
public:

typedef typename super_traits<T>::super super; //note this now!

virtual ~Handle () {}
virtual T & operator* () const = 0;
virtual T * operator-> () const = 0;

//not a template now, but still virtual
virtual super operator Handle<super> () const = 0;
};

In my opinion, super_traits is a superior solution, as you're defining the traits of derived classes without editing them. Also, you can define as many typedefs as you want; say your derived class has more than one base, you may want to define many typedefs, or preferably a typelist.


0 commentaires:

Enregistrer un commentaire