5

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.

Thomas Eding
  • 35,312
  • 13
  • 75
  • 106
  • Why not just make `operator Handle()` concrete in the base class? Could it really ever make sense for a different implementation to be provided? – Tony Delroy May 17 '11 at 04:34
  • My application needs (read: wants) various types of handles. Different memory (gc) pool types spit out different handles. Then again, I could be overengineering. Still an interesting question for me though. – Thomas Eding May 17 '11 at 04:37
  • @Tony: That would make `class Handle` use its derived class in its implementation. You could do it, but assuming there are actually multiple possible classes derived from `class Handle`, then it makes no sense. If there are not, then there should be no polymorphism to start with. – Keith May 17 '11 at 04:39
  • @trinithis: Have you considered using a template argument rather tha polymorphism to manage the allocator? Note that it doesn't have to be as complex as STL allocators. – Keith May 17 '11 at 04:41
  • I'm writing a compiler and want garbage collection in the language. I have GcPool as an abstract class. GcPool has a pure virtual construct(Class) function that returns Handle. I'm updating my first implementation of GcPool, CompactingPool to internally use handles after a little bootstrapping so it can allocate more handles in its own pool. But I want these handles with better types than GcObject, such as GcStack. Maybe this is a thing for explicit casts.... – Thomas Eding May 17 '11 at 04:48
  • @trinithis, I have suggestion; but before that I want to know a use case to know how you are going to use `operator Handle* ()`. You can update the question with same. I think you can get away with the `virtual` part of it. – iammilind May 17 '11 at 05:04
  • @trinithis: yeah... sorry - hadn't thought about or looked at the implementation. I can only imagine two approaches: meta-programming to enumerate base classes so Handle can explicitly provide separate virtual casting operators for each (i.e. overloading instead of template), or require ConcreteHandler to provide a factory supporting the relevant superclasses and pass the RTTI type id as a key indicating which to return.... – Tony Delroy May 17 '11 at 05:09
  • possible duplicate of [Templatized Virtual function](http://stackoverflow.com/questions/1277650/templatized-virtual-function) – AProgrammer May 17 '11 at 05:11
  • My answer to [Templatized Virtual function](http://stackoverflow.com/questions/1277650/templatized-virtual-function/1278328#1278328) show how to achieve most of the effects using type erasure. – AProgrammer May 17 '11 at 05:12

1 Answers1

4
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.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    @Nawaz, OP wants the effect of `virtual template` method. That's why he has mentioned as **psuedo code**. Can assume that he should be aware of error. – iammilind May 17 '11 at 04:44
  • @iammilind: Since virtual template is not possible, then its out of the question now. You cannot define virtual template. – Nawaz May 17 '11 at 04:45
  • That's restating the known problem... the code in the question's indicative of the desired functionality - Keith knows it doesn't work. What he wants is something functionally equivalent. – Tony Delroy May 17 '11 at 04:46
  • 2
    @Nawaz, Tony means that the questioner wants some functionality which **simulates** `virtual template`, – iammilind May 17 '11 at 04:49
  • @iammilind: It all depends on the definition of "some functionality". What do you mean by it? If you say "all functionality" of virtual template, that is not vague, but "some functionality" is vague. BTW, I'm just attempting to solve this problem. I don't understand what it doesn't achieve. – Nawaz May 17 '11 at 04:53
  • Haven't tried this yet, but this will only work if I cast only one class up at a time (if it returns a Handle* ... note pointer. Dont want slicing)? – Thomas Eding May 17 '11 at 05:03
  • a part of your response is on an external website (ideone). It may become useless if that site drops the snippet... – ascobol May 17 '11 at 05:05
  • @trinithis: As `super` is a typedef of the base (one class up), then yeah the cast/conversion will work as expected, i.e to one class up. If you want, you may define `super_super` typedef. – Nawaz May 17 '11 at 05:08
  • @DOWNVOTER: Specify the reason! – Nawaz May 17 '11 at 05:17