Following my answer to Unique type ID in C++, I have worked towards a "safer" version that I am posting here.
This is a lightweight type that can store a unique (also across compilation units) ID per type for use at runtime, without RTTI.
Instead of using a built-in type for ID representation that is also accessible to the end user, a specific class type_id_t
provides the external representation of the ID and encapsulates the actual storage type (a function pointer) that is not accessible.
A helper function template call type_id<T>()
returns a type_id_t
containing the ID of type T
.
Hence, the following operations are only provided:
- construction only by calling
type_id
function. - copy/move construction, as implicitly defined
- copy/move assignment, as implicitly defined
- comparison operators
==
and!=
between twotype_id_t
's
There is no default constructor for type_id_t
.
Here is the implementation:
class type_id_t
{
using sig = type_id_t();
sig* id;
type_id_t(sig* id) : id{id} {}
public:
template<typename T>
friend type_id_t type_id();
bool operator==(type_id_t o) const { return id == o.id; }
bool operator!=(type_id_t o) const { return id != o.id; }
};
template<typename T>
type_id_t type_id() { return &type_id<T>; }
It is interesting that function type_id
returns a (function) pointer to itself, encapsulated into a type_id_t
. No nasty type casting is necessary.
This is not a mechanism that provides runtime identification of a (polymorphic) object's type, but can be used as a low-level tool to build such functionality. I actually made this for the needs of my recent any, and then improved it.
Just for demonstration, we can store the ID of a number of types e.g. in a vector:
template<typename... T>
std::vector<type_id_t>
make_ids() { return {type_id<T>()...}; }
Later, we can compare the stored IDs to the ID of a given type:
template<typename T, typename A>
void comp_ids(const A& a)
{
for (auto i : a)
std::cout << (type_id<T>() == i) << " ";
std::cout << std::endl;
}
and get the following:
auto ids = make_ids<
int, bool, double const&, int&&, char(&)[8],
int, void(int), unsigned char**, std::vector<void(*)()>, double[4][8]
>();
comp_ids<int>(ids); // output: 1 0 0 0 0 1 0 0 0 0
Here is a live example.
Any comments are welcome.