0
101 Mar 15, 2007 at 15:04

Hi guys,

I’m having a little trouble …
Basically what I’d like to do is that a class template should return one of its parameters as a string like this:

#define ToStr(val) #val

template <class T>
cTest
{

T* mT;
//..some stuff using mT

char* GetName()
{
}

};


This compiles but GetName() returns “T”, not the actual parameter.
I tried to pass the parameter name as another template parameter:

template <class T,char* NAME=ToStr(T)>
...


This doesn’t compile because:
“invalid expression as a template argument for NAME”.
It won’t compile for anything I tried but a NULL ptr.

SO what’s the way to do this??

Thx,
ALex

7 Replies

0
101 Mar 15, 2007 at 19:23

I’m afraid you can’t do that.
You can however use typeid(T).name() provided you haven’t disabled RTTI.

0
167 Mar 15, 2007 at 20:58

The first way doesn’t work because the preprocessor (which is what handles #defines) works before the actual compiler even starts. So ToStr(T) gets substituted with “T” regardless of T’s status as a template parameter or anything else.

The second way doesn’t work because template parameters are only allowed to be typenames and enumerable types (basically, ints). This is because the compiler generates a new copy of the template for each combination of parameters. If things like pointers or floats were allowed, it would be extremely easy to accidentally create an enormous number of copies of the template.

0
101 Mar 15, 2007 at 21:14

The docu says that pointers are actually allowed as template arg. It seams an array cannot be defined so that it is accepted as a template arg.
(At least in visual studio 8)

I’d rather not use rtti.

I kinda found a way around it. I define a “template” class using a macro. Inside that I can just use T the way I like..and the way I think it should be :)

Alex

0
101 Mar 16, 2007 at 00:19

Just out of curiosity, why wont you use RTTI?

In the old days it used to have a big impact on code size, but now on MSVC and GCC are both pretty good with it.

In the past without RTTI I’ve used something like this:

template <class T>
cTest
{
char* GetName()
{
return T::GetName();
}

};


And for all classes that we want to use implement

class MyClass
{
static const char* GetName() { return "MyClass"; }
// .. lots more code
};


for every class that used the templated function.

It really wasn’t that many classes.

0
101 Mar 16, 2007 at 00:36

You can use the typeid thingy in VS without the need of enabling RTTI, as the types are statically typed. You’ll need RTTI for dynamic_casts and typeid’s of pointers/references to polymorphic types.

As for the template arguments, pointers and references are allowed but only for named objects with external linkage. A string literal is not such an object. This, however, does work:

template<const char *> struct S { };
const char MyString[] = "Hello World";
S<MyString> s;


Of course, that doesn’t solve your problem as preprocessing is completely independent of the actual semantics of the language :blink:

Also, there are thoughts in the committee to allow floats as template arguments if I’m not mistaken :)

0
101 Mar 16, 2007 at 14:13

@.oisin

I tried that..using your code I get:

.\TestMain.cpp(1219) : error C2970: ‘S’ : template parameter ‘unnamed-parameter’ : ‘MyString’ : an expression involving objects with internal linkage cannot be used as a non-type argument
.\TestMain.cpp(1217) : see declaration of ‘S’
.\TestMain.cpp(1218) : see declaration of ‘MyString’

I haven’t found a way to declare an array so that it is accepted as template argument.

@_dave

I wanted to avoid adding the GetName() function to each class as these are very generic classes used as events and as interface handler. So I have tons of instances that would require adding the function.

As for rtti,..well I kinda dislike enabling it for this single small thingy..I don’t need it anywhere else.

typeid(T).name() appears to be doing what I need…cool

Alex

0
101 Mar 16, 2007 at 16:13

Oh my bad, MyString isn’t seen as being external if it’s just const. It works if you drop the ‘const’ of MyString -or- if you define it as being external:

template<const char *> struct S { };
extern const char MyString[] = "Hello World";
S<MyString> s;  // works now