C++11 - уникальность typeid

В С++ 11 я использую это

typeid(T).name()

для моего собственного вычисления хэша. Мне не нужно, чтобы результат был одинаковым между запусками программы или компиляциями. Мне просто нужно, чтобы он был уникальным для типов. Я знаю, что он может возвращать одно и то же имя для разных типов, но обычно это константы, указатели и т. д. В моем случае T — это только class XY, struct XX или производные типы.

В таком случае, могу ли я предположить, что T будет уникальным?


person Martin Perry    schedule 01.11.2016    source источник
comment
Связано: stackoverflow. ком/вопросы/28861760/   -  person πάντα ῥεῖ    schedule 01.11.2016
comment
Единственный, кто может гарантировать, что T уникален, это вы. Вы уверены, что задали правильный вопрос?   -  person Lightness Races in Orbit    schedule 02.11.2016


Ответы (4)


Для сопоставления следует использовать std::type_index.

Класс type_index — это класс-оболочка вокруг объекта std::type_info, который можно использовать в качестве индекса в ассоциативных и неупорядоченных ассоциативных контейнерах. Отношения с объектом type_info поддерживаются через указатель, поэтому type_index является CopyConstructible и CopyAssignable.

person StoryTeller - Unslander Monica    schedule 01.11.2016
comment
И type_index безопасен таким образом? Например. не будет одинаковых type_index для разных типов? - person Martin Perry; 01.11.2016
comment
@MartinPerry тщательно изучает стандарт, нет твердого подтверждения его уникальности, но в 5.2.8 есть несколько подсказок. Кроме того, сам Страуструп предложил использовать адрес typeid (т.е. объекты type_info) для расширения системы typeinfo, также предполагая уникальность. - person Christophe; 01.11.2016
comment
@MartinPerry, соответствующая реализация может не делать ничего, кроме переадресации на std::type_info указатель. Тем не менее, использование type_index позаботится о мелочах, связанных с созданием type_info действительного ключа. Затем, если вы обнаружите, что специализация std::hash по умолчанию работает неоптимально, вы можете создать собственный тип Hasher (или с самого начала заменить текущий). - person StoryTeller - Unslander Monica; 01.11.2016

std::type_info::name определяется реализацией, поэтому не следует полагаться на его уникальность для разных типов.

Поскольку вы делаете это для вычисления хэша, вы должны вместо этого использовать std::type_info::hash_code. . Хотя это не гарантирует, что значения будут уникальными, стандарт говорит, что реализации должны пытаться возвращать разные значения для разных типов. Пока ваша реализация хеш-карты имеет разумную обработку коллизий, этого должно быть достаточно для вас.

person TartanLlama    schedule 01.11.2016
comment
std::type_info::hash_code также не гарантируется уникальностью для разных типов! - person themagicalyang; 01.11.2016
comment
@themagicalyang Правда? Стандарт говорит, что реализация должна возвращать разные значения для двух объектов type_info, которые при сравнении не равны. - person TartanLlama; 01.11.2016
comment
Я не проверял черновик как таковой, но cppreference говорит, что возвращает неопределенное значение, которое идентично объектам type_info, относящимся к одному и тому же типу. Других гарантий не дается. Например, одно и то же значение может быть возвращено для разных типов. Значение также может меняться между вызовами одной и той же программы. - person themagicalyang; 01.11.2016
comment
@TartanLlama см. также этот вопрос SO и для использования может/может/следует в стандартах, RFC 2119: должен четко разрешать реализацию отклоняться (даже если это маловероятно) - person Christophe; 01.11.2016
comment
TartanLlama видимо прав, в 18.7.2.8 об этом сказано. - person Hatted Rooster; 01.11.2016
comment
@ Кристоф А, это прекрасно объясняет. Я отредактирую свой ответ на предмет правильности. - person TartanLlama; 01.11.2016
comment
Ну, хэш не обязательно должен быть идеальным. Вы все равно должны сравнивать на равенство, несмотря ни на что... - person Kerrek SB; 01.11.2016

Как указано в cppreference:

Возвращает определенную реализацией строку символов с завершающим нулем, содержащую имя типа. Никаких гарантий не дается, в частности, возвращаемая строка может быть одинаковой для нескольких типов и меняться между вызовами одной и той же программы.

Так что нет, ты не можешь. Вы не можете ничего предполагать на самом деле.

Хотя hash_code() дает вам:

size_t hash_code() const noexcept;

7 Возвращает: Неуказанное значение, за исключением того, что в рамках одного выполнения программы оно должно возвращать одно и то же значение для любых двух объектов type_info, которые сравниваются равными.

8 Примечание: реализация должна возвращать разные значения для двух объектов type_info, которые при сравнении не равны.

Это означает, что hash_code() можно использовать для различения двух разных типов только в том случае, если operator== для type_info поддерживает это.

person Hatted Rooster    schedule 01.11.2016

Что вы можете сделать, так это взять адрес члена.

class HashBase {
    virtual intptr_t get() = 0;
};

template <typename T>
class Hash : HashBase {
    static const int _addr = 0;
    intptr_t get() override { return reinterpret_cast<intptr_t>(&_addr); }
};
person themagicalyang    schedule 01.11.2016
comment
C++17 гарантирует тот же адрес переменной inline с внешней связью (включая статические члены, если класс не находится в безымянном пространстве имен) во всех единицах перевода. При использовании C++17 (или более поздней версии) рассмотрите возможность создания статического члена inline для большей гарантии. - person monkey0506; 15.08.2019