Такое же имя типа, но не std:: is_same

Использование С++ (gcc 4.8.3) У меня есть 2 типа (T1 и T2), которые имеют странное свойство, что typeid(T1).name() и typeid(T2).name() являются одинаковыми, но std::is_same<T1, T2>::value - false.

Как это может быть? Как я могу подробнее исследовать, что может быть причиной?

Ответы

Ответ 1

Игнорируя полиморфизм, typeid() дает вам объект, представляющий статический тип выражения. Но есть некоторые элементы, которые игнорируются, когда дело касается типов выражений. Из [expr]:

Если выражение первоначально имеет тип "ссылка на T" (8.3.2, 8.5.3), тип устанавливается до T до любой дальнейший анализ. [...] Если prvalue изначально имеет тип "cv T", где T - это неквалифицированный не-класс, не-массив типа cv, тип выражение доводится до T до любого дальнейшего анализа.

В результате любые типы, которые отличаются только квалификацией или ссылкой на верхнем уровне, будут иметь один и тот же тип. Например, типы int, const int, int& volatile const int&& и т.д. Все дают вам то же самое typeid().

В основном, ваш первоначальный мыслительный процесс:

typeid(T) == typeid(U) <==> std::is_same<T, U>

Но правильная эквивалентность:

typeid(T) == typeid(U) <==> std::is_same<expr_type<T>, expr_type<U>>

где:

template <class T>
using expr_type = std::remove_cv_t<std::remove_reference_t<T>>;

Ответ 2

typeid игнорирует все cv-квалификаторы:

Во всех случаях cv-квалификаторы игнорируются typeid (т.е. typeid (T) == typeid (const T))

(ref)

Это означает, что typeid игнорирует все ссылки & и const (чтобы назвать несколько).

int i = 0;
const int&& j = 1;

if (typeid(i).hash_code() == typeid(j).hash_code()) //returns true
    std::cout << "typeid(int) == typeid(const int&&)";

Обратите внимание, что для сравнения 2 typeid s вы должны использовать либо typeid(T).hash_code(), либо std::type_index(typeid(T)), потому что только для этих двух функций гарантируется, что 2 одинаковых typeid будут одинаковыми. Сравнение ссылок не имеет такой гарантии, например.

Нет гарантии, что тот же экземпляр std:: type_info будет ссылаться на все оценки выражения typeid одного и того же типа, хотя std:: type_info:: hash_code этих объектов type_info будет идентичным, как было бы их std:: type_index.

(ref)


Как упоминалось в @Yakk, вы можете использовать std::remove_reference и std::remove_cv для получения желаемого поведения.

std::remove_reference удаляет все ссылки из T и std::remove_cv удаляет все const и volatile квалификаторы. Вы должны передать T через эти функции, прежде чем передавать их в std::is_same, так что std::is_same сравнивает только базовый тип (если есть) T1 и T2.