• Advertisement
Sign in to follow this  

Strings from C++ template arguments.

This topic is 4251 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 want to get an ASCII string for the name of the class to which a template argument is instantiated. The functionality should basically be enough to do this:
Quote:
template<typename T> void test(T arg){ cout << arg << " is of type " << STRING_THINGY(T) << "!\n"; } test(123); // prints "123 is of type int!\n"; test("abc") // prints "abc is of type char*!\n";
RTTI is no good since it's only for polymorphic types. Macros are no good since they're applied before templates are.

Share this post


Link to post
Share on other sites
Advertisement
Use typeid

It's a C++ keyword

the following will get what you want


template<class T>
class Test{
public:
Test(){
std::cout << typeid(T).name() << std::endl;
}


};


Share this post


Link to post
Share on other sites
Quote:
Original post by G-Force
Use typeid


Note that typeid does not depend on polymorphic types. It will only give you the base class if you typeid a pointer of that type and it isn't polymorphic, but that's not an issure here.

Also note that while on some platforms name() is legible, on others it is not. GCC spits out stuff like "v" for void, "u" for unsigned int, etc. for other primitives, and other manglings for classes. If legible types is a must, you must do the legwork yourself. Here's how I'd do it off the top of my head (disclaimer: untested, may not compile):

EDIT: Evil source tags like to eat my "\"s. Extra spaces added, delete them if copy/pasted :P. Also note you'll have to manually specialize types with commas in their name (e.g. std::vector< int , std::allocator< int > >) since it'll try to match that as a macro argument seperator (and extra parens don't work so well here)

template < typename T > struct type_information;

#define REGISTER_TYPE( type ) \
template <> struct type_information< type > { \
static const char * name() throw() { \
return #type; \
} \
};

REGISTER_TYPE( int )
REGISTER_TYPE( char )
...

template < typename T > void test( T arg ) {
cout << arg << " is of type " << type_information< T >::name() << end;
}



Share this post


Link to post
Share on other sites
Quote:
Original post by MaulingMonkey
Note that typeid does not depend on polymorphic types. It will only give you the base class if you typeid a pointer of that type and it isn't polymorphic, but that's not an issure here.


Then there's no reason to raise the issue and confuse matters.

Quote:
Also note that while on some platforms name() is legible, on others it is not. GCC spits out stuff like "v" for void, "u" for unsigned int, etc. for other primitives, and other manglings for classes. If legible types is a must, you must do the legwork yourself.


Use abi::__cxa_demangle().

Share this post


Link to post
Share on other sites
Quote:
Original post by Fruny
Quote:
Original post by MaulingMonkey
Note that typeid does not depend on polymorphic types. It will only give you the base class if you typeid a pointer of that type and it isn't polymorphic, but that's not an issure here.


Then there's no reason to raise the issue and confuse matters.


I was trying to clarify - I suspected the OP meant this when he refered to RTTI (since he wrote off RTTI as a possibility, and could not think of a way it applied except via the typeid operator), and wished to indicate that, no, typeid() works fine independantly of RTTI.

Quote:
Quote:
Also note that while on some platforms name() is legible, on others it is not. GCC spits out stuff like "v" for void, "u" for unsigned int, etc. for other primitives, and other manglings for classes. If legible types is a must, you must do the legwork yourself.


Use abi::__cxa_demangle().


Yes, probably better here :).

Share this post


Link to post
Share on other sites
Quote:
Original post by MaulingMonkey
I was trying to clarify - I suspected the OP meant this when he refered to RTTI (since he wrote off RTTI as a possibility, and could not think of a way it applied except via the typeid operator), and wished to indicate that, no, typeid() works fine independantly of RTTI.


Fair enough.

Share this post


Link to post
Share on other sites
Quote:
Original post by MaulingMonkey
I was trying to clarify - I suspected the OP meant this when he refered to RTTI (since he wrote off RTTI as a possibility, and could not think of a way it applied except via the typeid operator), and wished to indicate that, no, typeid() works fine independantly of RTTI.


Maybe it's some microsoft specific behaviour, but on MSDN doc for typeid is is said that:
Quote:
If the pointer does not point to a valid object, a __non_rtti_object exception is thrown, indicating an attempt to analyze the RTTI that triggered a fault (like access violation), because the object is somehow invalid (bad pointer or the code wasn't compiled with /GR).


(where /GR means that runtime type info is enabled)

The /GR documentation also states clearly that RTTI has to be enabled for whoever wants to use either dynamic_cast or typeid.

So this leaves me a bit confused... What do you think ?

Share this post


Link to post
Share on other sites
If one needs to demangle names in visual studio, use UnDecorateSymbolName in DbgHelp.dll. Just wanted to let you know in case your adventures require it.

Share this post


Link to post
Share on other sites
Quote:
Original post by janta
Maybe it's some microsoft specific behaviour, but on MSDN doc for typeid is is said that:
Quote:
If the pointer does not point to a valid object, a __non_rtti_object exception is thrown, indicating an attempt to analyze the RTTI that triggered a fault (like access violation), because the object is somehow invalid (bad pointer or the code wasn't compiled with /GR).


(where /GR means that runtime type info is enabled)

The /GR documentation also states clearly that RTTI has to be enabled for whoever wants to use either dynamic_cast or typeid.

So this leaves me a bit confused... What do you think ?


With regards to typeid(), this only applies to checking dereferenced pointers/references to polymorphic types. With /GR- on VS2k5E, this compiles and runs fine without warning:

#include <iostream>
using namespace std;

struct foo {};
struct bar : foo {};

int main () {
bar b;
foo * f = &b;
cout << "typeid( *f ).name() == " << typeid( *f ).name() << endl;
}





The result is foo, even though *f is of type bar - this is standard behavior, for foo is not polymorphic.

Adding a virtual table to foo:

#include <iostream>
using namespace std;

struct foo { virtual ~foo() {} };
struct bar : foo {};

int main () {
bar b;
foo * f = &b;
cout << "typeid( *f ).name() == " << typeid( *f ).name() << endl;
}





We get a warning compiling:

1>.\main.cpp(10) : warning C4541: 'typeid' used on polymorphic type 'foo' with /GR-; unpredictable behavior may result


And the program crashes at runtime. Switching both instances of "*f" (the pointer-to-polymorphic-type-unknown-until-runtime) with "foo" (the static type) or "b" (of a polymorphic type but determinable at compile time) and the program will compiles and runs fine with no warnings as expected (displaying foo and bar respectively).

All this said and done, since the OP is passing the type in question by value, unless he's making pointers for no good reason, typeid() will work fine, especially if he uses typeid(T), since the compiler can determine at compile time the type, and thus no dependance on Run Time Type Information.

Share this post


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

  • Advertisement