Sign in to follow this  

C++ Templates Question

This topic is 3577 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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 same
template <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]

Share this post


Link to post
Share on other sites
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


Share this post


Link to post
Share on other sites
Don't cast to void in the first place.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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...)

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
"Other than the iParam could you could also have separate Event.IDs and handlers for polygons and vertices."

Yeah, but this is exactly what I try to avoid, I need as few seperate events possible to maintain the bunch. It get tricky guaruateeing stuff when there are al lot of event etc.

"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"

Yes. In my view seeing events as objects with undo-redoable functions etc leads to way too much concepts and coding....

Share this post


Link to post
Share on other sites
Quote:
Original post by Kincaid
Yes. In my view seeing events as objects with undo-redoable functions etc leads to way too much concepts and coding....


The concepts are already there, you only need to find a way to implement them. You are basically looking for a way to perform your undo-redo based on the type of the event. There are two ways of doing this:

  1. You can use the language features which will achieve this binding with four lines of base class definition (define the class, two virtual functions and a virtual destructor) and an additional four lines per event type (define the function body for each function) in addition to the type-specific code.

    class Event {
    virtual void Undo(State &) = 0;
    virtual void Redo(State &) = 0;
    virtual ~Event();
    };


  2. You can implement dynamic dispatch yourself, which will involve at least a dozen lines of handling (manage RTTI, determine object type, cast to correct type, call the function) for each event in addition to the type-specific code and spread all over the place.

    I fail to see how one could even hope that the second method would require less work than the first method, let alone the debugging time for your in-house dynamic dispatch system.


Besides, the brittleness of a void-based solution prevents you from making any guarantees on even reasonably complex event systems, which is very bad news if you want your program to do any serious processing. By comparison, the entire dispatch system in the first method is guaranteed by the compiler, meaning you can concentrate on making your individual undo-redo functions respect their intended invariants.

Share this post


Link to post
Share on other sites
As ToohrVyk is saying, what about using inheritance?

template <class X>
class xclass : public container
{
X object;

void disconnect();
}

This way, after creating your different xclass objects, you can abstract them as a "container" class:

std::vector<container *> myStuff;
myStuff.push_back(new xclass<vertex *>());
myStuff.push_back(new xclass<polygon *>());

myStuff.at(0)->disconnect();
myStuff.at(1)->disconnect();

Share this post


Link to post
Share on other sites
Sign in to follow this