Когда использование 'typeid' является лучшим решением? - PullRequest
28 голосов
/ 19 июля 2011

Есть много причин не использовать typeid.Кроме использования элементов type_info (поведение, определяемое реализацией), обычно (всегда?) Возможно предоставить аналогичные функциональные возможности, используя другие функции языка C ++, например: перегрузка, виртуальные функции и т. Д.Использование, основанное на поведении, определяемом реализацией, есть ли у кого-нибудь реальный пример, где typeid - лучшее решение?

Ответы [ 6 ]

17 голосов
/ 19 июля 2011

Итак, кроме использования, которое зависит от поведения, определенного реализацией, есть ли у кого-нибудь пример из реальной жизни, где typeid - лучшее решение?

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

14 голосов
/ 20 июля 2011

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 к настоящему времени потерян, поэтому нидругие типы могут обеспечивать безопасность любого типа.

14 голосов
/ 20 июля 2011

При реализации мультиметодов (или множественных диспетчеризаций), когда фактический вызов выбирается, например, из карты, с использованием std::type_info* в качестве ключа.

7 голосов
/ 19 июля 2011

Напишите динамическое дерево, в котором вы можете во время выполнения изменять структуру дерева, в которой есть разные типы в каждой ссылке, для этого потребуется 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 { };

С типом связи, являющимся интерфейсом I * ... Поскольку вышеприведенное работает для любых значений типа T1, T2, T3, T4, мы могли бы также использовать аналогичные классы для любых функций T-> T1, T-> T2, T-> T3, T-> T4, и используйте этот тип функции в качестве узла дерева. Теперь у вас есть правильные выражения, описанные в динамическом дереве.

2 голосов
/ 19 июля 2011

Я использую его для проверки типа класса исключения в моем обработчике catch all.

// 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() является частью небольшой служебной библиотеки, в которой я неправильно получаю доступ к дополнительной информации об исключениях.Это очень удобно, когда функция выдает исключение, которое я должен поймать, но нет.Это определенно спасло много разочарований за эти годы, так как я сразу знаю тип исключения, которое требует покрытия.

2 голосов
/ 19 июля 2011

Вы можете использовать typeid для сравнения фактических типов двух объектов. Может быть полезно, если вы хотите проверить равенство двух объектов, и сначала убедитесь, что они относятся к одному и тому же типу (хотя я должен сказать, что я не видел, чтобы это делалось много, поэтому может быть веская причина, почему это не так хорошая идея ...).

...