45

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.

perimosocordiae
  • 17,287
  • 14
  • 60
  • 76
  • 5
    It's not possible as written. Depending on exactly what you're trying to achieve, it may be possible with templates though. Can you give us a bit more context of what problem you're trying to solve? – jalf Apr 01 '10 at 17:19
  • In c++0x that specific function is possible, but there's never a place it is useful because the type information is lost when the original variable is. – Dennis Zickefoose Apr 01 '10 at 18:49
  • The only thing I can think of to store types polymorphicaly in C++ would be _type erasure_. – sbi Apr 02 '10 at 16:14

8 Answers8

34

No, this is not possible in C++.

The RTTI typeid 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
  • 174,939
  • 50
  • 355
  • 478
  • 1
    The name isn't portable, though. – Michael Aaron Safyan Apr 01 '10 at 22:49
  • 14
    It is portable, just not between compilers. An application compiled with GCC on linux will have the same type names as GCC on windows, but not the same as the VS compiler. – RamblingMad Apr 12 '14 at 06:01
  • @Thomas Is this http://en.cppreference.com/w/cpp/types/type_info the operator you're talking about? This isn't an operator, right? But rather a class that stores the result of typeid()? – David Doria Feb 09 '16 at 21:24
  • 1
    Fail on my part. It's [`typeid`](http://en.cppreference.com/w/cpp/language/typeid). Editing... (11 upvotes without anyone mentioning this glaring mistake), thanks for spotting! – Thomas Feb 10 '16 at 08:02
27

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.

Andrew
  • 5,839
  • 1
  • 51
  • 72
Michael Aaron Safyan
  • 93,612
  • 16
  • 138
  • 200
  • Hi Micheal. I'm almost there with your snippet. The cast function in the derived class returns a void pointer in your code. How do I get the T* as desired? – degski Feb 15 '16 at 16:03
  • 1
    You can explicitly in the caller if you know that the object is of the correct type. However, the reflective API that operates on any type can't reasonably have strongly-typed methods; the methods for the general type representation would need to operate on weakly-typed objects (void* in conjunction with some record of the type). – Michael Aaron Safyan Feb 15 '16 at 18:48
  • 2
    What does method `cast` achieve here? It only returns a `void*` pointer which has to be explicitly `static_cast` to a specific class before it can be used. – X... Dec 03 '21 at 19:26
12

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
  • 6,433
  • 5
  • 33
  • 51
9

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
  • 339,232
  • 124
  • 596
  • 636
3

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
  • 35,646
  • 15
  • 94
  • 131
  • Strictly speaking, there is no guarentee that ’shared_pointer’ 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 Apr 01 '10 at 20:31
  • duly noted and fixed. I'll add comments about "Foo" – wheaties Apr 01 '10 at 21:02
  • You don't need `Foo` at all, you can just do `boost::shared_ptr`, with appropriate deleters. – user1095108 Mar 19 '13 at 12:05
3

Today I had a similar problem while coding:
I had the need to store a polymoriphic data type (here named refobj) over wich call functions of the concrete classes implementing it. I need a solution that doesn't cast the variable explicitly because I need to reduce the amount of code.

My solution (but I haven't tested it yet) looks similar to a previous answer. Actually is quite an experimental solution. It look like this...

// 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!
Caleb
  • 124,013
  • 19
  • 183
  • 272
David
  • 31
  • 1
1

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
  • 22,566
  • 11
  • 59
  • 78
1

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
  • 56,849
  • 17
  • 98
  • 154