tipos - try on c++
Almacenar un tipo en C++ (8)
¿Es posible almacenar un nombre de tipo como una variable de C ++? Por ejemplo, como este:
type my_type = int; // or string, or Foo, or any other type
void* data = ...;
my_type* a = (my_type*) data;
Sé que el 99.9% del tiempo hay una mejor manera de hacer lo que se quiere sin recurrir a lanzar punteros a los vacíos, pero tengo curiosidad de que C ++ permita este tipo de cosas.
Hoy tuve un problema similar durante la codificación:
Tuve la necesidad de almacenar un tipo de datos polimorífico (aquí denominado refobj) sobre las funciones de las clases concretas que lo implementan. Necesito una solución que no emita la variable explícitamente porque necesito reducir la cantidad de código.
Mi solución (pero todavía no la he probado) se parece a una respuesta anterior. En realidad es toda una solución experimental. Se parece a esto ...
// interface to use in the function
class Type
{
public:
virtual void* getObj()const=0;
};
// here the static_cast with the "stored" type
template<typename T> class TypeImpl : public Type
{
public:
TypeImpl(T *obj) {myobj=obj;}
virtual void* getObj()const{ return static_cast<T*>(myobj); }
private:
T* myobj;
};
// here the type that will contain the polimorific type
// that I don''t want to cast explicitly in my code
Type *refobj;
// here the "user code "
void userofTypes()
{
( refobj->getObj() ).c_str();
// getObj() should return a string type over which
// calling string concrete functions ...let''s try!
}
void main()
{
refobj=new TypeImpl < string > ( new string("hello") );
userofTypes();
}
// it might seem absurd don''t cast refobj explicitly, but of
// course there are situation in which it can be useful!
Los tipos no son objetos en C ++ (donde están en Ruby, por ejemplo), por lo que no puede almacenar instancias de un tipo. En realidad, los tipos nunca aparecen en el código de ejecución (RTTI es solo almacenamiento extra).
Basado en su ejemplo, parece que está buscando typedefs.
typedef int Number;
Number one = 1;
Number* best = (Number*) one;
Tenga en cuenta que un typedef no está almacenando el tipo; es aliasing el tipo.
No como está escrito, pero podrías hacer algo similar ...
class Type
{
public:
virtual ~Type(){}
virtual void* allocate()const=0;
virtual void* cast(void* obj)const=0;
};
template<typename T> class TypeImpl : public Type
{
public:
virtual void* allocate()const{ return new T; }
virtual void* cast(void* obj)const{ return static_cast<T*>(obj); }
};
// ...
Type* type = new TypeImpl<int>;
void* myint = type->allocate();
// ...
Este tipo de cosas se puede ampliar según las funciones que necesite.
No puedes hacer eso en C ++, pero puedes usar el impulso de cualquier biblioteca y luego probar el tipo que contiene. Ejemplo:
bool is_int(const boost::any & operand)
{
return operand.type() == typeid(int);
}
No, esto no es posible en C ++.
El operador de typeid
IDTI de typeid
permite obtener información sobre los tipos en tiempo de ejecución: puede obtener el nombre del tipo y verificar si es igual a otro tipo, pero eso es todo.
No, no puede almacenar el tipo directamente como lo desea, sino que puede almacenar el nombre del tipo.
const char* str = typeid(int).name();
Supongo que cada vez que planeabas usar esa variable para la comparación, en ese momento podrías comparar la variable str
con el name()
de los tipos.
const char* myType = typeid(int).name();
//....
//Some time later:
if(!strcmp(myType, typeid(int).name()))
{
//Do something
}
Sí, si lo codificas tú mismo.
enum Foo_Type{
AFOO,
B_AFOO,
C_AFOO,
RUN
};
struct MyFoo{
Foo_Type m_type;
Boost::shared_ptr<Foo> m_foo;
}
Como se comenta a continuación, lo que omití fue que todos estos tipos "foo" tendrían que estar relacionados con Foo. Foo sería, en esencia, tu interfaz.
Un proceso mejor es tener una clase base común que contenga un método de carga y una interfaz para los cargadores . Esto permitiría que otras partes del programa carguen datos genéricamente sin el conocimiento de la clase descendiente:
struct Load_Interface;
struct Loader
{
virtual void visit(Load_Interface&) = 0;
}
struct Load_Interface
{
virtual void accept_loader(Loader& l)
{
l.visit(*this);
}
};
Este diseño evita la necesidad de conocer los tipos de objetos.