4

I'd like to do something like this:

template <typename T>
constexpr ::std::size_t type_name_hash()
{
  return ::std::hash<::std::string>()(typeid(T).name());
}

Now, I know neither hash nor string are constexpr, but this could be worked around, assume they are constexpr. What I want to ask is, if RTTI was turned on, should a constexpr function computing a hash of typeid(T).name() still produce a compile-time constant? How about when RTTI is turned off?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
user1095108
  • 14,119
  • 9
  • 58
  • 116

2 Answers2

6

typeid(type-id) and typeid(expr) can both be used in constant expressions, except if (as has been mentioned) expr's result is a glvalue of polymorphic class type.

However, since none of type_info's standard members are constexpr (including the hash_code() method), you cannot do anything with that object except take its address. There's not even a guarantee in the standard that the object is initialized. And even taking the address is only barely useful because there is no guarantee that typeid() has the same result when used with the same type. E.g. the following assertion may fail:

static_assert(&typeid(int) == &typeid(int), "Multiple type_infos for int");

This is a contrived example, but it's not unheard of that typeid(T) yields different results for the same T in multiple shared libraries used in a program, and possibly even in different translation units.

Arne Vogel
  • 6,346
  • 2
  • 18
  • 31
4

What part of Run-Time Type Identification do you think works at compile-time? The rules for constant expressions disallow:

— a typeid expression (5.2.8) whose operand is a glvalue of a polymorphic class type;

so your template would only work for some types.

And with RTTI turned off you can't use typeid at all.

C++11 already provides a mechanism to hash a type:

return ::std::hash<::std::type_index>()(::std::type_index(typeid(T)));

But it's not going to be a constant expression for all types.

You could use the type_index of a pointer to each type, as a pointer is not a polymorphic class type and will still give a unique type:

return ::std::hash<::std::type_index>()(::std::type_index(typeid(T*)));

Now the problem is "only" that the type_index constructor is not constexpr and neither is the hash function.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • Thanks, I see another case of forgotten `constexpr` specifiers, I can't do anything with `RTTI` at compile time, except take a pointer. – user1095108 May 29 '14 at 09:47
  • How about just taking a pointer of the `type_info`, that `typeid` returns and just that as "hash". – user1095108 May 29 '14 at 10:06
  • There's no guarantee the address of the `type_info` is a constant (it could be dynamically allocated as needed) in which case you can't take its address in a `constexpr` function – Jonathan Wakely May 29 '14 at 11:19
  • Yes, there, as the returned `type_info` must be static. – user1095108 May 29 '14 at 11:42
  • No, the standard doesn't say that. It only says "The lifetime of the object referred to by the lvalue extends to the end of the program." – Jonathan Wakely May 29 '14 at 15:14
  • 2
    A typeid expression with glvalue of a polymorphic class type is disallowed, but all other uses of typeid are (by extension) allowed. The example code uses only a type-id. In fact, GCC thinks even "int x; constexpr auto &tx = typeid(x);" is a-ok. – Arne Vogel Mar 26 '15 at 20:08
  • 1
    I don’t think this answers OP’s question. `typeid(T)` is obviously *never* going to run into the problem described here, because `T` isn’t an expression, it’s a type name. Consequently, the required operations *could* all be `constexpr` (but they aren’t). – Konrad Rudolph Oct 18 '15 at 19:59