2012-06-17 16 views
13

He encontrado una solución simple en algún lugar de Internet para una clase de identidad sin C++ RTTI incorporado.Identidad de clase sin RTTI

template <typename T> 
class Identity { 
public: 
    static int64_t id() 
    { 
     static int64_t dummy; 
     return reinterpret_cast<int64_t>(&dummy); 
    } 
}; 

Cuando necesitamos algo de ID de clase, sólo tiene que utilizar:

Identity<OurClass>::id(); 

Me pregunto, ¿hay colisiones? ¿Puede devolver el mismo ID para las diferentes clases, o la identificación diferente para las mismas clases? He intentado este código con g ++ con diferentes valores de optimización, todo parece estar bien.

+0

En principio, sí. No hay garantía de que un puntero de función tenga el mismo tamaño que un 'int'. –

+1

Esto es relevante para mis intereses ... –

+0

Para evitar el problema anterior, sería mejor poner una variable estática 'int' en esa plantilla de función miembro estática y devolver un puntero a * que *. El compilador optimizará la función de todos modos. – Electro

Respuesta

12

Primero: hay un tipo tal integral que se hace específicamente para contener punteros:

  • intptr_t
  • y en C++ 11 uintptr_t

En segundo lugar, aunque en la práctica en gcc son iguales, el tamaño de un puntero a un objeto y el tamaño de un puntero de función (o puntero a miembro) bien podrían ser diferentes. Por lo tanto, sería mejor utilizar un objeto específico en lugar del método en sí (para la conformidad estándar).

En tercer lugar, solo le da identidad, mientras que RTTI es mucho más rico, ya que conoce todas las subclases a las que se puede convertir un objeto determinado, e incluso permite conversiones cruzadas en sucesiones virtuales.

Sin embargo, la versión corregida puede ser útil supongo:

struct Foo { 
    static intptr_t Id() { 
     static boost::none_t const Dummy = {}; 
     return reinterpret_cast<intptr_t>(&Dummy); 
    } 
}; 

Y en jerarquías, que tiene una función virtual devolver ese ID.

Para completar, mencionaré que Clang y LLVM tienen su propia forma de tratar la identificación de objetos sin RTTI. Es posible que desee leer sobre su forma de implementar isa, cast y dyn_casthere.

+0

Upvoted para una explicación completa. – Electro

+0

gracias, pero no entendí, ¿por qué el tamaño de un puntero a un objeto y el tamaño de un puntero a la función podrían ser diferentes? ¿Puede dar un ejemplo? – pproger

+0

@pproger: el tamaño de los punteros de función de miembros virtuales a menudo difiere en tamaño de los punteros normales. Sin embargo, esto es específico del compilador, puede leer más sobre esto en este excelente artículo del proyecto de código: http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible –

-1

Esta solución arroja un puntero a la función int. No hay garantía de que este puntero encaje en un int, aunque en la práctica sizeof(void *) == sizeof(void (*)()) <= sizeof(int)

Edición: Mi mal. En x86_64 sizeof(int) = 4, sizeof(void (*)()) = 8, por lo que las colisiones son posibles y son impredecibles.

Puede convertir a una integral de tamaño adecuado, pero aún así es un comportamiento indefinido teóricamente.

+0

Eso no siempre es cierto en la práctica; prueba x86-64. –

+0

ok, he editado el código. ¿ahora que? – pproger

0

Esta versión evita un comportamiento indefinido (y advertencias del compilador):

template <typename T> 
class Identity { 
public: 
    static const int* id() { static const int id = 0; return &id; } 
}; 
+0

no necesito valor de retorno como puntero. quiero int :) – pproger

+0

¿Por qué te importa si es un puntero o no? – Electro

+0

yo no. autor del código do) – pproger

Cuestiones relacionadas