tags:

views:

244

answers:

8

Is it possible to store a type name as a C++ variable? For example, like this:

type my_type = int; // or string, or Foo, or any other type
void* data = ...;
my_type* a = (my_type*) data;

I know that 99.9% of the time there's a better way to do what you want without resorting to casting void pointers, but I'm curious if C++ allows this sort of thing.

+3  A: 

No, this is not possible in C++.

The RTTI typeinfo operator allows you to get some information about types at runtime: you can get the type's name and check whether it is equal to another type, but that's about it.

Thomas
The name isn't portable, though.
Michael Aaron Safyan
A: 

As Neil said in his comment, this is not allowed. From what I know of C, I'd say that if you want to call a type by something different, use a #define preprocessor macro. However, I don't know if you can do the same thing in C++.

#define my_type int

...

void* data = ...;
my_type* a = (my_type*) data
Matt Ball
Sure, you can do the same thing in C++. If you want to get shot, that is...
John Dibling
IMHO, you get what you deserve for using C++.
Matt Ball
LOL, maybe true.
John Dibling
+1  A: 

Types are not objects in C++ (where they are in Ruby, for instance), so you cannot store instances of a type. Actually, types never appear in the executing code (RTTI is just extra storage).

Based on your example, it looks like you're looking for typedefs.

typedef int Number;
Number one = 1;
Number* best = (Number*) one;

Note that a typedef isn't storing the type; it is aliasing the type.

Andres Jaan Tack
`Number` isn't a variable, i.e., it's meaning can't be changed at run-time.
sbi
Noted. Based on his example, though, I don't think he's actually looking for storage.
Andres Jaan Tack
You're right that my example isn't doing anything a typedef can't do, but I would have ultimately liked to store the type (as a member of a class, say). Sorry for the confusion.
perimosocordiae
+2  A: 

No you can't store the type directly as you want, but you can instead store the name of the type.

const char* str = typeid(int).name();

I guess whenever you planned to use that variable for comparison, you could instead at that time compare the str variable against the name() of the types.

const char* myType = typeid(int).name();

//....

//Some time later:
if(!strcmp(myType, typeid(int).name()))
{
  //Do something
}

More info available here

Brian R. Bondy
Except that name() isn't guaranteed to be the same across platforms!
Michael Aaron Safyan
@Michael: I did not suggest saving it to a file
Brian R. Bondy
+1  A: 

Yes, if you code it yourself.

enum Foo_Type{
    AFOO,
    B_AFOO,
    C_AFOO,
    RUN
};

struct MyFoo{
    Foo_Type m_type;
    Boost::shared_ptr<Foo> m_foo;
}

as commented below, what I left out was that all these "foo" types would have to be related to Foo. Foo would, in essence, be your interface.

wheaties
Strictly speaking, there is no guarentee that ’shared_pointer<Foo>’ is large enough to store all those different types unless ’Foo’ is related to them in some way. Also, ’_AFOO’ is an illegal identifier.
Dennis Zickefoose
duly noted and fixed. I'll add comments about "Foo"
wheaties
+3  A: 

You can't do that in C++, but you can use the boost any library then test for the type it holds. Example:

bool is_int(const boost::any & operand)
{
  return operand.type() == typeid(int);
}

http://www.boost.org/doc/libs/1_42_0/doc/html/any/s02.html

Chris H
Cool, I hadn't seen that before.
perimosocordiae
+1  A: 

Not as written, but you could do something 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();
// ...

This kind of thing can be extended depending on what features you need.

Michael Aaron Safyan
A: 

A better process is to have a common base class containing a load method, and an interface for loaders. This would allow other parts of the program to load data generically without knowledge of the descendant class:

struct Load_Interface;

struct Loader
{
  virtual void visit(Load_Interface&) = 0;
}

struct Load_Interface
{
  virtual void accept_loader(Loader& l)
    {
        l.visit(*this);
    }
};

This design avoids the need to know the types of objects.

Thomas Matthews