The road for reflection: Tagging types

Something like a month ago I wrotea post introducting the reflection engine I’m writing as part of a C++ course for people in the game programming master degree of my university. Why me, an undergrad that has the end of his CS grade faaaaaaar away from his horizon, is giving such a course is a mater of another post (A post on Why I hate the university sooooooo much “…).

Writing a reflection engine has two primary goals:

  • Game programmers these days are used to a wide pipeline of tools that ease with game development, in a way most of them doesn’t even write their own game engine but only do the game . That is, game programming has become a game itself. Regardless you think this is good or not (I think is not, game programming is not such a challenging/interesting task that was the old days. But others may think that now everybody could write his own game, which is good.), the point is that most game programming courses focus on tools instead of game enignes/design, and people exit the course (the master in this case) without knowing how these tools work. This is true even in courses focused on engine programming, since most people don’t have the required programming skills to deep into the techniques involved in the implementation of AAA engines nor frameworks such as unity.

  • It’s fun. Nothing more, nothing less.

So the idea is to show people how systems like Unreal Engine’s blueprint integration could work, and have fun in the process.

“Could” is an important word here, As I usually tell people in my classes, what I show is just the way I did the thing, not THE WAY to do it. I took decissions based on my own context (It should be “teachable”, I’m lazy, etc), but others might follow different approaches. That’s what being an engineer means, right?

As the roadmap in the previous post shows, one of the first tasks we have to aboard is the way we store C++ type information for our engine, in a way it can be used at runtime to instance objects, check function signatures, etc. Today, I will show you what I did to store C++ type information at compile time and use that info for tagging C++ types .


Since what we are doning with runtime reflection is a kind of dynamic type system for C++, the first thing we need is a way to store type information so it can be checked at runtime, compare types for equality, etc.

Type intType = getType<int>(); Type charType = getType<char>();  assert(intType != charType);

C++ already ships a similar feature in its Standard Library by means of the <type_info> header: RunTime Type Information , or RTTI for friends.

C++ RTTI works by storing type information (Its name, a “unique” identifier, etc) as part of the program binary so we can query this info at runtime with the typeid operator :

#include <type_info>  auto intType = typeid(int);  std::cout << intType.name(); // Prints "int" ?

However standard rtti has some caveats:

  • It can be queried at runtime only: Please read that again. I find so funny that a language that uses its “static type system” almost as an advertising motto cannot query the name of a type at compile time. Amazing.

  • No practical guarantees: The name that .name() gives is mangled, so it’s almost useless in most scenarios. Of course you can demangle the name with your vendor API, but having to maintain a portable demangling API is something I would like to avoid. I did once, and was… well, let’s follow. Also the supposed “unique id” that .hash_code() returns is only guaranteed to be the same for equal types, but is not guaranteed that different types yield different hashes . Kind of useful.

  • Size bloat: AAA game programmers often dislike RTTI since it bloats their executable by adding an entry in the symbol table for each type. RTTI data is usually backed in classes as a “negative” entry in the vtable of the type, like:

     class Foo {     virtual void f(); };  class Bar : public Foo {     void f() override;     int i; };  Foo* bar = new Bar();                                  Bar vtable                               +---------------+            Bar object         | Bar type info | bar ---> +------------+       +---------------+          | vtable ptr | ----> |    &Bar::f    |          +------------+       +---------------+          |    int i   |          +------------+ 

    But, really, I don’t care. I’m sure deploying to such constrained systems like game consoles is hard. But, come on… I think this is a common case of bias like the “exceptions are slow” topic. Of course YMMV, but from my experience exceptions and RTTI worked pretty damn well on embedded devices.


To solve the two issues above (As I said, I don’t consider the third an issue) my friend Jonathan “foonathan” Müller and I wrote the ctti library . CTTI (From “ Compile Time Type Information ”) aims to provide both demangled type names and unique hashes at compile time, thanks to C++11 constexpr:

#include <ctti/type_id.hpp>  constexpr auto intType = ctti::type_id<int>(); constexpr auto charType = ctti::type_id<char>();  static_assert(intType != charType, "What???");  std::cout << intType.name(); // Gives "int"

How it works

This morning as part of the pre-work to write this post I found myself checking the code and documentation of Don Williamson’s clReflect engine , a clang-based reflection engine very similar to this one.

Williamson was the lead engine programmer of games such as Fable and Splinter Cell Conviction.

Here ’s a great gamasutra article where he shares the reflection API they wrote for Conviction


From clReflect wiki :

Simulate C++ RTTI type name retrieval

To relieve the dependency on the typeinfo header, a function similar to this can be introduced:

template <typename TYPE> const char* GetTypeName() { #ifdef _MSC_VER    return __FUNCSIG__; #else    return __PRETTY_FUNCTION__; #endif }

This trick is exactly what CTTI does. Using a constexpr function CTTI “parses” __FUNCSIG__ and similar expressions at compile time to get the name of the type out of the string. “Parses” is a very generous word I think. What we did is to wrap vendor-specific __FUNCSIG__ -like expressions and check the format of its output, so we can get an specific substring (The type name) out of the string.

This is a bit tricky: Did you notice I never said “string literals” nor “macros”? It’s because such constructs ( __PRETTY_FUNCTION__ , __FUNCSIG__ , etc) are not macros nor string literals but implicitly declared identifiers similar to standard __func__ (From C99, added to C++ with C++11), which is probably one of the worst specified points of the standard…

The weird part of CTTI was to write a constexpr string class able to build substrings at compile time, with C++11 constexpr only, supporting Visual Studio . Cannot bold that last item enough. That was such a pain in the ass. See THE ISSUE .

But, what’s a constexpr class? What’s constexpr ?


Feel free to jump over this if you already know about constexpr .

constexpr is feature available since C++11 which gives the option of writing C++ code to be evaluated (Actually interpreted by the compiler) at compile time. Here’s an example:

constexpr float add(float x, float y) {     return x + y; }  constexpr float FLOAT_CONSTANT = add(0.0f, 1.0f);

This has lots of benefits, since until C++11 the only way to do complex computations at compile time was by using hard to read/maintain/easy-to-throw-up template meta-programming techniques. And this only involved computations on integral types. I once wrote a floating point template for TMP, since I wanted to do 3d transformations at compile time. Trust me, you wouldn’t like to put that kind of code in production…

In the example above, add() is a constexpr function and FLOAT_CONSTANT a constexpr constant. A constexpr function is guaranteed to be evaluated at compile time as long as its arguments can, like in this case. Else, functions are “downgraded” into a normal C++ function, to be evaluated at runtime. The constexpr constant there is just a way to force constexpr evaluation of add() : These are constants that have to be initialized at compile time, else compilation fails.

constexpr not only applies to plain C functions, but to member functions, even constructors . So you end up having the ability to write classes and instancing objects that are completely evaluated at compile time . That’s so cool.

Here’s an example of a useful constexpr member function: std::array::size() :

std::array<ichar, 1024> buffer;  read(file, &buffer[0], buffer.size());

No more #define LENGTH (x) (sizeof(x)/sizeof(&x[0])) tricks. No more C arrays please. It’s 2016 and there’s still people introducing bugs in the linux kernel because of this… Hey, would you like to hear a TCP joke?

A constexpr class is just a class that has at least one constexpr declared contructor, so the compiler can make instances at compile time:

class string { public:     template<std::size_t N>     constexpr string(const char (&string_literal)[N]) :         _str{string_literal},         _size{N}     {}      constexpr std::size_t size() const     {         return _size;     } private:     const char* _str;     std::size_t _length; };  static_assert(string("foo").size() == string("bar").size(), "???");

For more info about constexpr clases, and constexpr in general, I recommend this series on compile time string parsing.

Tagging types

Now that we have unique IDs and demangled names, let’s pack all useful type info in a TypeInfo constexpr class:

class TypeInfo { public:     TypeInfo(ctti::type_id_t id, std::size_t sizeOf, std::size_t alignment) :         _id{id},         _sizeof{sizeOf},         _alignment{alignment}     {}      constexpr const char* name() const     {         return _id.name().c_str();     }      constexpr ctti::type_id_t id() const     {         return _id;     }      constexpr std::size_t sizeOf() const     {         return _sizeof;     }      constexpr std::size_t alignment() const     {         return _alignment;     }      template<typename T>     static constexpr TypeInfo get()     {         return {             ctti::type_id<T>(),             sizeof(T),             alignof(T)         };     }      friend constexpr bool operator==(TypeInfo lhs, TypeInfo rhs)     {         return lhs.id() == rhs.id();     }      friend constexpr bool operator!=(TypeInfo lhs, TypeInfo rhs)     {         return !(lhs.id() == rhs.id());     }  private:     const ctti::type_id_t _id;     const std::size_t _sizeof;     const std::size_t _alignment; };  constexpr TypeInfo intType = TypeInfo::get<int>(); constexpr TypeInfo charType = TypeInfo::get<char>();  static_assert(intType != charType, "???");  std::cout << intType.name(); // prints "int"

What’s next?

Today we learnt how to write a compile-time type info class with all the information we will need to follow with the reflection engine. In next posts we will implement MetaType , the class that manages runtime types and knows how to instance and destroy objects dynamically.

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » The road for reflection: Tagging types

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址