6

Why is the following code guaranteed to be a unique typeID ?!

using TypeId = uintptr_t; 

template < typename T >
static TypeId GetTypeId()
{
   static uint32_t placeHolder;
   return (reinterpret_cast<TypeId>(&placeHolder));
} 

Source

I don't understand why this is not just a kind of random memory location as a kind of "misused"... Thanks for answers in advance.

Filip Roséen - refp
  • 62,493
  • 20
  • 150
  • 196
lifeOfPI
  • 318
  • 1
  • 8
  • 3
    The compiler will instantiate a copy of the template function for each type you call it with, and each of these instantiations has its own unique `placeHolder`, so you get a different address for each type. – T.C. Jun 16 '14 at 21:27
  • 2
    _"I don't understand why this is not just a kind of random memory location"_ It is, so to speak. But that doesn't matter. It's unique and consistent for each type. – Drew Dormann Jun 16 '14 at 21:29
  • so I did understand it right, its just a random number that is guaranteed being unique.... is there any advantage in doing this? Is there any kind of advantage in not using RTTI? – lifeOfPI Jun 16 '14 at 21:33
  • [I used this technique](http://stackoverflow.com/a/2650805/103167) long before that CodeProject article, and I'm not the first. – Ben Voigt Jun 16 '14 at 21:37

1 Answers1

8

Introduction

You are correct that the implementation abuses the "random memory location" of a block-scope static variable, but that doesn't mean that the guarantee you are talking about doesn't hold: the returned from GetTypeId<T> will be unique for each instantiation of it.

Note: One should however be aware of the fact that uintptr_t is not guaranteed to be available for every platform. A fully portable way to implement the function would be to return a void*, which is guaranteed to be able to hold every address of every object in a program.


The distinct address guarantee...

In C++ there's a guarantee that every object must reside at a unique address, unless we are talking about an object which is a subobject if another. In such case they may have the same address (and in cases the sharing of address is required, as with standard-layout classes and their first data-member).

1.8p6 The C++ object model [intro.object]

Unless an object is a bit-field or a base class subobject of zero size, the address of that object is the address of the first byte it occupies. Two objects that are not bit-fields may have the same address if one is a subobject of the other, or if at least one is a base class subobject of zero size and they are of different types; otherwise, they shall have distinct addresses.


Static variables in functions...

We also have an explicit clause saying that every specialization of a function-template that includes a static variable has its own unique copy of said static variable:

14.8p2 Function template specializations [temp.fct.spec]

Each function template specialization instantiated from a template has its own copy of any static variable.

Since a variable that is declared static is unique to every instantiation of GetTypeId<T>, where T is an arbitrary type, every object named placeHolder in this template specialization must an unique object.

It must be an unique object, and with that; it must have a distinct address.


Note 1) In C++11 we have std::type_index which fulfils the guarantee you are after.
Note 2) The C++11 standard draft n3337 has been used as a reference in this post.

Community
  • 1
  • 1
Filip Roséen - refp
  • 62,493
  • 20
  • 150
  • 196