C ++: type_info para distinguir tipos
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:
-
std::type_info::name
debe devolver dos cadenas diferentes para dos tipos diferentes. -
std::type_info::before
hay que decir que esType1
antesType2
o-exclusivaType2
es antesType1
.// like this: typeid(T1).before( typeid(T2) ) != typeid(T2).before( typeid(T1) )
-
Dos especialización diferente de la misma clase de plantilla se consideran diferentes tipos.
-
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 almacenartype_info
s algún lugar (por ejemplo: en unstd::map
)? La única manera que tenga unstd::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!=
ybefore
en la mayoría de los compiladores comunes? Supongo que sólo debe comparar un valor. Y qué tan rápido estypeid
? -
Tengo un
A
clase con unvirtual bool operator==( const A& ) const
. DesdeA
tiene muchas subclases (algunos de los cuales son desconocidos en tiempo de compilación), me sobrecarga que el operador virtual en cualquierB
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?
Solución
Después de un rápido vistazo a la documentación, diría que:
-
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.
-
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.
-
Cada instancia de una clase de plantilla es un tipo diferente. La especialización hacer excepciones.
-
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. Sitypedef 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:
- Usted no tiene esta garantía con respecto a
std:type_info::name
. La norma indica únicamente que la rentabilidad dename
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. - No sé, y la norma no es clara en este punto, por lo que no podría basarse en tales comportamientos.
- que uno debe ser un definitivo 'Sí' para mí
- 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 envoltorioTypeInfo
en su Moderno C ++ Diseño libro. Tenga en cuenta que los objetos devueltos portypeid
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; }