type_info example c++ typeid typeinfo

example - C++: type_info para distinguir los tipos



typeid c++ (5)

Después de un rápido vistazo a la documentación, diría que:

  1. std :: type_info :: name siempre devuelve dos cadenas diferentes para dos tipos diferentes, de lo contrario, significa que el compilador se perdió a sí mismo al resolver tipos y no debería usarlo más.

  2. La referencia dice: "antes devuelve verdadero si el tipo precede al tipo de rhs en el orden de intercalación. El orden de intercalación es solo un orden interno mantenido por una implementación particular y no está necesariamente relacionado con las relaciones de herencia o el orden de declaración". Por lo tanto, tiene la garantía de que ningún tipo tiene el mismo rango en el orden de colación.

  3. Cada creación de instancias de una clase de plantilla es un tipo diferente. La especialización no hace excepciones.

  4. Realmente no entiendo lo que quieres decir. Si te refieres a algo como tener typedef foo bar; en dos unidades de compilación separadas y esa barra es la misma en ambas, funciona de esa manera. Si te refieres a typedef foo bar; typedef int bar; typedef foo bar; typedef int bar; , no funciona (excepto si foo es int).

Sobre tus otras preguntas:

  • Debe almacenar referencias a std :: type_info, de envolverlo de alguna manera.
  • Absolutamente sin idea sobre el rendimiento, asumo que los operadores de comparación tienen tiempo constante a pesar de la complejidad del tipo. Antes debe tener una complejidad lineal en función del número de tipos diferentes utilizados en su código.
  • Esto es realmente extraño. Debería sobrecargar a su operator== lugar de hacerlo virtual y anularlo.

Sé que los compiladores tienen mucha libertad para implementar el comportamiento de las funciones std::type_info .

Estoy pensando en usarlo para comparar tipos de objetos, así que me gustaría asegurarme de que:

  1. std::type_info::name debe devolver dos cadenas diferentes para dos tipos diferentes.

  2. std::type_info::before debe decir que Type1 es anterior a Type2 exclusive-o Type2 es anterior a Type1 .

    // like this: typeid(T1).before( typeid(T2) ) != typeid(T2).before( typeid(T1) )

  3. Dos especializaciones diferentes de la misma clase de plantilla se consideran tipos diferentes.

  4. Dos diferentes typedef -iniciones del mismo tipo son el mismo tipo.

Y finalmente:

  • Como std::type_info no se puede copiar, ¿cómo puedo almacenar type_info s en algún lugar (por ejemplo: en un std::map )? ¿La única forma de tener un std::type_info siempre asignado en algún lugar (por ejemplo: en la pila o en una variable estática / global) y usar un puntero a él?

  • ¿Qué tan rápido son operator== , operator!= Y before en los compiladores más comunes? Supongo que solo deberían comparar un valor. ¿Y qué tan rápido es el tipo de typeid ?

  • Tengo una clase A con un virtual bool operator==( const A& ) const . Dado que A tiene muchas subclases (algunas de las cuales son desconocidas en tiempo de compilación), sobrecargo ese operador virtual en cualquier subclase B esta manera:

    virtual bool operator==( const A &other ) const { if( typeid(*this) != typeid(other) ) return false; // bool B::operator==( const B &other ) const // is defined for any class B return operator==( static_cast<B&>( other ) ); }

    ¿Es esta una forma aceptable (y estándar) de implementar dicho operador?


Estándar 18.5.1 (Clase type_info):

La clase type_info describe información de tipo generada por la implementación. Los objetos de esta clase almacenan efectivamente un puntero a un nombre para el tipo, y un valor codificado adecuado para comparar dos tipos para la igualdad o el orden de clasificación. Los nombres, la regla de codificación y la secuencia de clasificación para los tipos no están especificados y pueden diferir entre los programas .

Desde mi entendimiento:

  1. No tiene esta garantía con respecto a std:type_info::name . El estándar solo establece que el name devuelve un NTBS definido por la implementación , y creo que una implementación conforme podría muy bien devolver la misma cadena para cada tipo.
  2. No lo sé, y el estándar no está claro en este punto, así que no confiaría en tal comportamiento.
  3. Ese debería ser un ''sí'' definitivo para mí
  4. Ese debería ser un ''sí'' definitivo para mí

Respecto al segundo conjunto de preguntas:

  • No, no puede almacenar un type_info . Andrei Alexandrescu propone un envoltorio TypeInfo en su libro Modern C ++ Design . Tenga en cuenta que los objetos devueltos por typeid tienen almacenamiento estático, por lo que puede almacenar los punteros de forma segura sin preocuparse por la vida útil del objeto.
  • Creo que puedes asumir que la comparación de type_info es extremadamente eficiente (realmente no hay mucho para comparar).

Las respuestas actuales para las preguntas 1 y 2 son perfectamente correctas, y son esencialmente solo detalles de la clase type_info, no tiene sentido repetir esas respuestas.

Para las preguntas 3 y 4, es importante comprender qué es exactamente un tipo en C ++ y cómo se relacionan con los nombres. Para empezar, hay un montón de tipos predefinidos, y esos tienen nombres: int, float, double . A continuación, hay algunos tipos construidos que no tienen nombres propios: const int, int*, const int*, int* const . Hay tipos de función int (int) y tipos de puntero a función int (*)(int) .

A veces es útil dar un nombre a un tipo sin nombre, que es posible utilizando typedef . Por ejemplo, typedef int* pint o typedef int (*pf)(int); . Esto introduce un nombre, no un nuevo tipo.

Los siguientes son los tipos definidos por el usuario: estructuras, clases, uniones. Hay una buena convención para darles nombres, pero no es obligatorio. No agregue un nombre así con typedef, puede hacerlo directamente: struct Foo { }; En lugar de typedef struct {} Foo; . Es común tener definiciones de clase en los encabezados, que terminan en múltiples unidades de traducción. Eso significa que la clase se define más de una vez. Este sigue siendo el mismo tipo y, por lo tanto, no se le permite jugar trucos con macros para cambiar las definiciones de los miembros de la clase.

Una clase de plantilla no es un tipo, es una receta para tipos. Dos instancias de una plantilla de clase única son tipos distintos si los argumentos de la plantilla son tipos (o valores) diferentes. Esto funciona recursivamente: Dado la template <typename T> struct Foo{}; , Foo<Foo<int> > es el mismo tipo que Foo<Foo<Bar> > si y solo si Bar es otro nombre para el tipo int .


Puedes almacenarlo así.

class my_type_info { public: my_type_info(const std::type_info& info) : info_(&info){} std::type_info get() const { return *info_;} private: const std::type_info* info_; };

EDITAR:

Estándar de C ++ 5.2.8.

El resultado de una expresión typeid es un lvalue de tipo estático const std :: type_info ...

Lo que significa que puedes usarlo así.

my_type_info(typeid(my_type));

La función typeid devuelve un lvalue (no es temporal) y, por lo tanto, la dirección del type_info devuelto siempre es válido.


Type_info es una implementación definida, así que realmente no confiaría en ella. Sin embargo, según mis experiencias con g ++ y MSVC, las suposiciones 1,3 y 4 se mantienen ... no estoy realmente seguro acerca del # 2.

¿Hay alguna razón por la que no puedas usar otro método como este?

template<typename T, typename U> struct is_same { static bool const result = false; }; template<typename T> struct is_same<T, T> { static bool const result = true; }; template<typename S, typename T> bool IsSame(const S& s, const T& t) { return is_same<S,T>::result; }