compile time typeid for every type

This's not a constexpr function, but if there is not the constraint for the types to be persistent over multiple executions, you can use CRTP idiom as an alternative approach to achieve the same result.
It follows a minimal, working example:

#include <cstddef>
#include <iostream>

struct BaseClass {
protected:
    static std::size_t next() noexcept {
        static std::size_t counter = 0;
        return counter++;
    }
};

template<class D>
struct Base: public BaseClass {
    static std::size_t type() noexcept {
        static std::size_t type_ = BaseClass::next();
        return type_;
    }
};

struct A: public Base<A> { };
struct B: public Base<B> { };

int main() {
    std::cout << A::type() << std::endl;
    std::cout << B::type() << std::endl;
}

This way you have a base class from which to derive for all those types for which you would like to have an unique identifier.


Another way, this time involving a constexpr function, would be to use a well known hash function like in the following example (where I used the FNV v1a):

#include <cstdint>
#include <iostream>

static constexpr uint32_t offset = 2166136261u;
static constexpr uint32_t prime = 16777619u;

constexpr uint32_t helper(uint32_t partial, const char *str) {
    return str[0] == 0 ? partial : helper((partial^str[0])*prime, str+1);
}

constexpr uint32_t hash_str(const char *input) {
    return helper(offset, input);
}

struct MyClassA { static constexpr uint32_t type = hash_str("MyClassA"); };
struct MyClassB { static constexpr uint32_t type = hash_str("MyClassB"); };

int main() {
    std::cout << "MyClassA: " << MyClassA::type << std::endl;
    std::cout << "MyClassB: " << MyClassB::type << std::endl;
}

The drawbacks:

  • conflicts can happen
  • error-prone (at least, from my point of view)
  • pretty invasive a sollution

The main advantage is that you can use this solution if you need the types to be the same over different executions (as an example, if you have to store them somewhere and use them again after a while).


You could use some tricks as shown in this answer.

There's even a library called ctti that utilizes the same trick, it should work out of the box

static_assert(ctti::type_id<int>() != ctti::type_id<float>(), "compile-time type-id comparison");

constexpr auto hash = ctti::type_id<int>().hash();

Tags:

C++

C++14