Pregunta

Yo sé que los compiladores tienen mucha libertad en la ejecución de la conducta funciones std::type_info.

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

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

  2. std::type_info::before hay que decir que es Type1 antes Type2 o-exclusiva Type2 es antes Type1.

    // like this:
    typeid(T1).before( typeid(T2) ) != typeid(T2).before( typeid(T1) )
    
  3. Dos especialización diferente de la misma clase de plantilla se consideran diferentes tipos.

  4. dos diferentes typedef-initions del mismo tipo son del mismo tipo.

Y por último:

  • Desde std::type_info no es copiable, ¿cómo podría almacenar type_infos algún lugar (por ejemplo: en un std::map)? La única manera que tenga un std::type_info algún lugar siempre asignado (por ejemplo: en la pila o en un / variable global estática)? Y utilizar un puntero a ella

  • ¿A qué velocidad son operator==, operator!= y before en la mayoría de los compiladores comunes? Supongo que sólo debe comparar un valor. Y qué tan rápido es typeid?

  • Tengo un A clase con un virtual bool operator==( const A& ) const. Desde A tiene muchas subclases (algunos de los cuales son desconocidos en tiempo de compilación), me sobrecarga que el operador virtual en cualquier B subclase de 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) para poner en práctica dicho operador?

¿Fue útil?

Solución

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

  1. std :: :: type_info nombre siempre devuelve dos cadenas diferentes para dos tipos diferentes, de lo contrario, significa que el compilador se perdió, mientras que la resolución de tipos y no se debe utilizar más.

  2. Referencia dice: "antes del regreso de cierto si los precede Tipo El tipo de RHS en el orden de clasificación El orden de clasificación es sólo un orden interno mantenido por una aplicación en particular y no está necesariamente relacionada a las relaciones de herencia o auto de declaración. ". Por lo tanto, usted tiene la garantía de que no hay tipos tienen el mismo rango en el orden de clasificación.

  3. Cada instancia de una clase de plantilla es un tipo diferente. La especialización hacer excepciones.

  4. Yo realmente no entiendo lo que quieres decir. Si se refiere a algo como tener typedef foo bar; en dos unidades de compilación separadas y que la barra es la misma en ambos, funciona de esa manera. Si typedef foo bar; typedef int bar; media, que no funciona (excepto si foo es int).

Sobre sus otras preguntas:

  • Usted debe almacenar referencias a std :: type_info, de la envoltura de algún modo.
  • Absolutamente ninguna idea sobre el rendimiento, supongo que los operadores de comparación tienen tiempo constante a pesar de la complejidad tipo. Antes debe tener complejidad lineal en función del número de diferentes tipos usados ??en el código.
  • Esto es realmente extraño en mi humilde opinión. Usted debe sobrecargar su operator== en lugar de hacer lo virtual y anularlo.

Otros consejos

Norma 18.5.1 (Clase type_info):

El type_info clase describe Tipo la información generada por el implementación. Los objetos de esta clase almacenar de manera efectiva un puntero a un nombre para el tipo, y un valor codificado adecuado para comparar dos tipos de la igualdad o para cotejar. La nombres, la codificación de la regla y de clasificación secuencia para tipos son todos no especificado y pueden diferir entre los programas .

A mi entender:

  1. Usted no tiene esta garantía con respecto a std:type_info::name. La norma indica únicamente que la rentabilidad de name un NTBS definido por la implementación , y creo que una aplicación se ajuste bien podría devolver la misma cadena para cada tipo.
  2. No sé, y la norma no es clara en este punto, por lo que no podría basarse en tales comportamientos.
  3. que uno debe ser un definitivo 'Sí' para mí
  4. que uno debe ser un definitivo 'Sí' para mí

En cuanto a la segunda serie de preguntas:

  • No, no se puede almacenar un type_info. Andrei Alexandrescu propone un envoltorio TypeInfo en su Moderno C ++ Diseño libro. Tenga en cuenta que los objetos devueltos por typeid tienen almacenamiento estático para que pueda almacenar de forma segura los punteros sin preocuparse de duración del objeto
  • Creo que se puede asumir que la comparación type_info son extremadamente eficientes (en realidad no hay mucho para comparar).

Se puede almacenarla como este.

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_;
};

EDIT:

C ++ estándar 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 se puede utilizar de esta manera.

my_type_info(typeid(my_type));

La función typeid devuelve un valor izquierdo (que no es temporal) y por lo tanto la dirección de la type_info devuelto es siempre válida.

Las respuestas actuales para las preguntas 1 y 2 son perfectamente correcta, y son esencialmente sólo detalles de la type_info clase -. Ocioso repetir esas respuestas

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

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

A continuación son tipos definidos por el usuario: estructuras, clases, uniones. Hay una convención bueno darles nombres, pero no es obligatorio. No añadir dicho nombre con un typedef, puede hacerlo directamente: struct Foo { }; en lugar de typedef struct {} Foo;. Es común tener definiciones de clases en las cabeceras, que terminan \ en múltiples unidades de traducción. Eso quiere decir que la clase se define más de una vez. Esto sigue siendo del mismo tipo, y por lo tanto no están autorizados para jugar trucos con macros para cambiar las definiciones de miembros de clase.

Una clase de plantilla es no un tipo, es una receta para este tipo. Dos instanciaciones de una plantilla de clase única son tipos distintos si los argumentos de plantilla diferentes tipos (o valores). Esto funciona de forma recursiva:. Dada template <typename T> struct Foo{};, Foo<Foo<int> > es del mismo tipo que Foo<Foo<Bar> > si y sólo si Bar es otro nombre para el tipo int

type_info es definida por la implementación, así que realmente no confiar en ella. Sin embargo, basado en mis experiencias usando g ++ y MSVC, suposiciones 1,3 y 4 bodega ... no muy seguro sobre # 2.

¿Hay alguna razón no se puede utilizar 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; }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top