Идентификация класса без RTTI
Я нашел простое решение где-то в Интернете в классе идентификации без встроенного С++ RTTI.
template <typename T>
class Identity {
public:
static int64_t id()
{
static int64_t dummy;
return reinterpret_cast<int64_t>(&dummy);
}
};
Когда нам нужен идентификатор класса, мы просто используем:
Identity<OurClass>::id();
Мне интересно, есть ли какие-то столкновения? Может ли он возвращать одинаковый идентификатор для разных классов или другой идентификатор для тех же классов? Я пробовал этот код с g++ с разными значениями оптимизации, все выглядит нормально.
Ответы
Ответ 1
Прежде всего: существует такой интегральный тип, который специально предназначен для указания указателей:
-
intptr_t
- и в С++ 11
uintptr_t
Во-вторых, хотя на практике на gcc они равны, размер указателя на объект и размер указателя на функцию (или указатель на член) могут быть разными. Поэтому было бы лучше использовать конкретный объект, а не сам метод (для стандартного соответствия).
В-третьих, он дает вам только тождество, в то время как RTTI намного богаче, поскольку он знает обо всех подклассах, к которым может быть применен данный объект, и даже позволяет перекрестные кавычки или касты по виртуальному наследованию.
Тем не менее, исправленная версия может быть полезна, я думаю:
struct Foo {
static intptr_t Id() {
static boost::none_t const Dummy = {};
return reinterpret_cast<intptr_t>(&Dummy);
}
};
И в иерархиях, имеющих функцию virtual
, возвращающую этот идентификатор.
Для полноты я упомянул, что Clang и LLVM имеют свой собственный способ справиться с идентификацией объекта без RTTI. Вы можете прочитать об их способе реализации isa
, cast
и dyn_cast
здесь.
Ответ 2
Эта версия позволяет избежать поведения undefined (и предупреждений компилятора):
template <typename T>
class Identity {
public:
static const int* id() { static const int id = 0; return &id; }
};
Ответ 3
Это решение бросает указатель на int
. Нет гарантии, что этот указатель вписывается в int
, хотя на практике sizeof(void *) == sizeof(void (*)()) <= sizeof(int)
Изменить: Мне плохо. На x86_64 sizeof(int) = 4
, sizeof(void (*)()) = 8
, поэтому возможны столкновения и непредсказуемы.
Вы можете отличить интеграл от соответствующего размера, но все же это поведение undefined теоретически.