Когда используется "typeid" лучшее решение?
Существует много причин не использовать typeid
. Помимо использования членов type_info
(поведение, определяемое реализацией), обычно (всегда?) Возможно обеспечить аналогичную функциональность, используя другие возможности языка С++, например: перегрузка, виртуальные функции и т.д.
Итак, исключая использование, которое зависит от поведения, определенного реализацией, есть ли у кого-нибудь пример реального мира, где typeid
- лучшее решение?
Ответы
Ответ 1
boost::any
использует typeid
для реализации any_cast
.
template<typename T> any_cast(const any& other) {
if(typeid(T) != other.type()) throw bad_any_cast();
//...actual cast here...
}
Вы не можете быть уверены, что T
является полиморфным, поэтому dynamic_cast
не может быть и речи, и закрытый тип в вызове boost::any
уже потерян, поэтому ни одна из других трансляций не может предоставить какой-либо вид безопасности типа.
Ответ 2
Итак, исключая использование, которое зависит от поведения, определенного для реализации, есть ли у кого-нибудь пример реального мира, где typeid - лучшее решение?
Я иногда использую его в выводах отладки, чтобы проверить, что аргумент шаблона, переданный моей функции, действительно относится к заданному типу. Это имеет смысл в моем случае, так как фактический аргумент шаблона, переданный моей функции, генерируется специализированным метафоном, и я хочу убедиться, что используется правильный метафокус.
Ответ 3
При реализации многотодовых (или нескольких отправлений), где фактический вызов выбирается из, например, карту, используя std::type_info*
в качестве ключа.
Ответ 4
Напишите динамическое дерево, в котором вы можете на этапе выполнения изменить структуру дерева, где в каждой ссылке есть разные типы, для этого потребуется typeid. dynamic_cast недостаточно.
Изменить: Здесь несколько деталей:
class I {
public:
virtual std::string type() const=0;
virtual void *value() const=0;
};
template<class T>
class Impl : public I
{
public:
Impl(T t) : t(t) { }
std::string type() const { return typeid(T).name(); }
void *value() const { return &t; }
private:
T t;
};
И затем постройте дерево из них:
template<class Node, class Link>
class Tree { };
С типом ссылки, являющейся интерфейсом я *... Так как приведенное выше действие для любых значений типов T1, T2, T3, T4, мы могли бы также схожими классами для любых функций T- > T1, T- > T2, T- > T3, T- > T4 и использовать этот тип функции как Node дерева. Теперь у вас есть правильные выражения, описанные в динамическом дереве.
Ответ 5
Вы можете использовать typeid
для сравнения фактических типов двух объектов. Может быть полезно, если вы хотите проверить равенство двух объектов и сначала убедитесь, что они одного и того же типа (хотя я должен сказать, что я не видел, чтобы это было сделано много, поэтому может быть веская причина, почему это не так хорошая идея...).
Ответ 6
Я использую его для проверки типа класса исключения в моем обработчике catch.
// fudge vtable existence (thrown exceptions must have one)
class StubException
{
virtual ~StubException();
};
.....
catch(...)
{
StubException *e = getExceptionObject(); // compiler/rt specific
std::string s = typeid(e).name();
...
throw;
}
Функция getExceptionObject()
является частью небольшой библиотеки-утилиты, которую я неправильно использую для получения дополнительной информации об исключениях. Это очень удобно, когда функция генерирует исключение, которое я должен улавливать, но это не так. Это определенно сэкономило много разочарований на протяжении многих лет, так как я сразу же знаю тип исключения, которому требуется покрытие.