Jump to content
  • Advertisement
Sign in to follow this  
Hodgman

[C++] Get type name without RTTI

This topic is 2538 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

For a while, I've been looking for a way to get the name (as a c-string) of a template parameter, without using RTTI. Speaking with digital, he mentioned the idea of using the __FUNCTION__ macro and some string parsing, so I had a go and it seems to work quite easily.

This is pretty hacky, so I'm hoping some of you fellow C++ users can tear apart it's weaknesses and expose the down-sides for me.

My first concern is that this relies on MSVC's implementation of the __FUNCTION__ macro, which includes the class name. On GCC I'd have to use __PRETTY_FUNCTION__ instead. I'm assuming any decent compiler will have some kind of macro that I can use for this purpose...

template<class T>
struct TypeName
{
static void Get(const char*& begin, const char*& end)
{
begin = __FUNCTION__;
for(++begin; *begin && *(begin-1) != '<'; ++ begin);
for(end = begin; *end; ++ end);
for(; end > begin && *end != '>'; -- end);
}
};


Example usage:
const char* begin=0, *end=0;
TypeName<Foo>::Get(begin, end);
assert(end>begin);
assert(end-begin < 128);
char buf[128];
memcpy(buf, begin, end-begin);
buf[end-begin] = 0;
printf(buf);//prints Foo

Share this post


Link to post
Share on other sites
Advertisement
You can use typeid(T).name() without RTTI.
Hmm, I'd assumed that disabling RTTI (with /GR-) would kill [font="Lucida Console"]typeid[/font], but it seems in MSVC2008, it still works fine on compile-time expressions like this!
This was my previous method, but I'd assumed I was relying on RTTI.

I wonder if other compilers (e.g. GCC with fno-rtti) will act the same way though? Also, GCC's implementation of type_info::name requires unmangling, but I guess I'm bound to end up with lots of "[font="Lucida Console"]#ifdef compilerABC[/font]" when doing this kind of stuff... wink.gif

[edit]GCC gives: "error: cannot use typeid with -fno-rtti"

Share this post


Link to post
Share on other sites
Right, the behavior of typeid() is compiler specific when you disable RTTI (disabling RTTI isn't part of C++ standard). Regarding your original code, it looks good to me. Thanks for sharing the trick (:


Cheers, Jarkko

Share this post


Link to post
Share on other sites
What do I get for:
typedef std::basic_string<int> MyCustomString;
typedef MyCustomString SomethingStrange;

TypeName<SomethingStrange>::get()

How about:
TypeName<std::pair<std::vector<int>, std::string>>::get();


Or:TypeName<printf>::get();


There is a reason why C++ error messages are the mess they are.

A minor nitpick as well - RTTI means Run-time type information, FUNCTION and templates are both compile-time.

The best that can be had reliably is resolving the type down to basic types and printing that. Which is also what the compiler reports for errors. Going from that to what was actually used in code can be difficult to impossible.

Another gotcha is that long symbol names may cause problems with compiler and buffer sizes, causing the name to be incomplete or perhaps even crash.

Share this post


Link to post
Share on other sites
What do I get for:
[font="Courier New"]typedef std::basic_string<int> MyCustomString;
typedef MyCustomString SomethingStrange;
TypeName<SomethingStrange>::get()[/font]
Both of the above methods (using [font="Courier New"]__FUNCTION__[/font] or [font="Courier New"]typeid[/font]) return "[font="Lucida Console"]class std::basic_string<int,struct std::char_traits<int>,class std::allocator<int> >[/font]"
How about: [font="Courier New"]TypeName<std::pair<std::vector<int>, std::string>>::get();[/font][/quote]Both return "[font="Lucida Console"]struct std::pair<class std::vector<int,class std::allocator<int> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >[/font]"
Or: [font="Courier New"]TypeName<printf>::get();[/font][/quote]As expected: [font="Lucida Console"]'printf' is not a valid template type argument for parameter 'T'[/font].
I don't want to know the types of types that aren't types.

I'm not sure what you're getting at, but these are the results I'm looking for. I want to know the actual type of a template argument, regardless of typedefs, etc.


A minor nitpick as well - RTTI means Run-time type information, FUNCTION and templates are both compile-time.[/quote]The point of these shenanigans is to be able to disable the standard RTTI and instead use a home-made lightweight implementation.
If I can determine the type of a parameter at compile time, then I can make a simple RTTI system from that - hence the title, Get type name without RTTI.
Basically, if you create a perfect hash from these strings, then you get a bare bones RTTI system that lets you do fast type comparisons (but nothing else).

Share this post


Link to post
Share on other sites
Light weight in what sense? If you're interested in reducing the number of compiler generated structures added to your binary, on MSVC you may also have to disable exception handling because MSVC uses many of the same internal structures to support both.

Share this post


Link to post
Share on other sites
There is a compiler option in Visual Studio (sorry name of it escapes me at the moment) that can remove duplicate functions, ie functions which have similar or same functionality even with different types. I would be wary (or at least check) that the template function name is not changed by this and gives incorrect information about the typename T.

Share this post


Link to post
Share on other sites
I've used a similar trick in the past. To the best of my knowledge, no significant evil problems ever came out of it.

Share this post


Link to post
Share on other sites
I just discovered that instead of __FUNCTION__ giving, e.g.:
[font="Courier New"]TypeName<std::pair<std::vector<int>, std::string>>::get[/font]
Some compilers give you:
[font="Courier New"]TypeName<T>::get [with T = std::pair<std::vector<int>, std::string>][/font]
which is still parsable, but it seems the parsing routing is going to be quite different depending on the compiler.

Light weight in what sense? If you're interested in reducing the number of compiler generated structures added to your binary, on MSVC you may also have to disable exception handling because MSVC uses many of the same internal structures to support both.
Lightweight in the sense that I can check that a type is what I expect it to be with a predictable/low amount of storage and a predictable/low amount of work. I also only need to check for exact type matches, not inheritance/interface matches.
The standard RTTI implementation is unpredictable, depending on the compiler's implementation, and MSVC's implementation of type-comparison is extremely slow.

Also, type_info objects are non-copyable, which is usually worked around by wrapping them in a PIMPL class. However, predictable memory access patterns are important for this library (e.g. for NUMA support), which makes the default RTTI implementation quite expensive/unusable from a memory-access perspective.
e.g. when I invoke [font="Courier New"]operator==[/font] on two [font="Courier New"]type_info[/font]s, which memory locations are read from? If I can't answer/control that, then I can't use them.

I'm using the assumption that many users of a game-oriented library will likely have RTTI and exceptions disabled, so I need to support that.
Most of the game projects I've been involved with professionally have had both exceptions and RTTI disabled, so I would like to design this system in a way where people can use it without being forced to change their compiler settings.

Share this post


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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!