C++ Templates Question

Started by
12 comments, last by small_duck 16 years ago
Hello I have a template class template <class X> class xclass { X object; } Upon instantiation, you specify the type X for the object; Is it possible, given an instance, to retrieve the type of X??? The reason I ask is, I have a template container class, where the object can be vertices or polygons (from which I make a list for vertices, and one for polygons). But (at some level) I want to treat all containers as containers without looking at the fact that that it is either a vertex or polygon container... Each container has a disconnect() function, regardless of its type (vertex\polygon). At some point I use void pointers to pass data. When I get this data, I must typecast it back from void*. e.g. (int*) data. For my containers I have two types xclass<vertex>* and xclass<polygon>*. Since they both have a disconnect() function, it seems to work by just choosing one, but this doesn't seem 'the proper way'. I guess i would like to cast it to xclass<X> again, but how exactly (use template here again?) I hope it's clear what I mean..... thanx in advance for any help
Advertisement
If you wish to treat all containers in the same way at runtime, the proper way provide a common interface and have them implement that interface.

Since the implementation of a template has access to the type (through the type parameter which you have called X in your example), I fail to see the problem of working with that type in the implementation.

To answer your initial question, the common way to know the value of X outside the object is to use a member typedef.

template <class X>class xclass{  typedef X value_type;};


Thus, xclass<X>::value_type is X.
From my understanding your problem isn't so much you want to find out the type of X, more that you want to treat all XClasses the same, presumably in a function.

Here's one solution to that:

// A function that treats all XClass<> containers the sametemplate <class X>void genericFunction(XClass<X> & container){    // Instantiating a type of X is easy:    X myObjectInstance;}


[Edited by - dmatter on April 1, 2008 9:32:26 AM]
Hello
Thanx, thats a very neat little trick, and I'll definitly be using that one.
However it doesn't help me passing containers via void* pointers.

lets say i have two void pointer, each to a container.

void* a = xclass<x>*
void* b = xclass<y>*

two function, each for a container type
function f (xtyped)
function f (ytyped)

I would like to call f ( (xclass) a/b )for both void pointers, since the handling will resolve via type. (I can also call f for all containers normally)
But now I need to specifically cast the a* to xclass<x> typed containers, and the b* tp xclass<y> typed containers.

Thanx


Don't cast to void in the first place.
you can do it in two different ways:

you can enable your compiler's RTTI (RunTime Type Information) which gives you a TypId and TypeName methods, which allows you to retrieve any information you want from any object.

an easier solution is to just assume that any class passed to the template will implement a GetType function, of course, the template will fail to compile if the class you pass to it does not have that method.

template <class X>
class xclass
{
X object;

int GetType() { return object.GetType(); }
}

there are other methods, like using abstract base classes with virtual methods, but, for what you want, these ones are enough.
Just don't cast to void, 99% of the time there's no need for it and I can't see why you want to with these either.
The void pointers are in context of an undo/redo system im currently working on. I need a generic way to represent 'events'. I choose a 3-fold specification for all events, consisting of a void* 'object', void* 'state', int iParam.

By means of an event.ID I know what event it is, so I know what information is supposed to be stored in the object and state pointer. From there I run all my actions, undoing and redoing them.

e.g. deletion of a vertex(-container) is object=container, msgID CONNECT, iParam = 0 says disconnect, iParam = 1 says connect.
(but this message applies to all containers, also polygons)

So I guess void* are pretty much waranted here...
(again, I need things to be very generic)

I know templates will be said to apply here too, but it seems overkill here since a few simple void pointer per action-specification suit my needs beautifully. Only little problem here combining it with templates...

(my 'ugly' current way is to pass a number to iParam that specifies to cast back to vertex-container or polygon-container. So all'n'all I seek to reduce my switch to a one-liner...)

Quote:Original post by Kincaid
(my 'ugly' current way is to pass a number to iParam that specifies to cast back to vertex-container or polygon-container.

Yeah, casting to void means you lose type information, if you later need that information back you need to have stored it separately.
Other than the iParam could you could also have separate Event.IDs and handlers for polygons and vertices.

Essentially what you're doing here is ad-hoc runtime polymorphism using a void pointer rather than a reference to a base-class for undo/redo-able objects.
You could use an actual function binding system like boost::function with boost::bind and keep everything type safe without ever punting to void pointers.

This topic is closed to new replies.

Advertisement