tags:

views:

220

answers:

10

I want to be able to do the following:

I have an array of strings that contain data types:

string DataTypeValues[20] = {"char", "unsigned char", "short", "int"};

Then later, I would like to create a variable of one of the data types at runtime. I won't know at compile time what the correct data type should be.

So for example, if at runtime I determined a variable x needed to be of type int:

DataTypeValues[3] x = 100;

Obviously this won't work, so how could I do something like this?

+9  A: 

The simple answer is that you can't - types need to be known at compile time in C++. You can do something like it using things like boost::any or unions, but it won't be pretty.

anon
Actually, since the set of types is bounded and known at compile time, the appropriate class here would be `boost::variant<char, unsigned char, short, int>`. Still not pretty, but a whole lot better. You no longer can stuff a string in.
MSalters
+2  A: 

You can't. This kind of run-time metaprogramming is not supported in C++.

sepp2k
+1  A: 

The only thing you can do is manually loop through the types and compare each individual one. There's also the potential to use a factory object here - but that would involve the heap.

DeadMG
As the types are not related by inheritance, using a factory would be difficult, so say the least.
anon
There is that. Boost::Variant is probably the easiest solution here.
DeadMG
+10  A: 

you would have to use unions to achieve something like that, but handling unions is a very difficile matter, so you should choose a container class which wraps the union logic behind an interface like Boost.Variant or Qts QVariant

smerlin
Variant is definitely the way to go, it's almost free too (compared to any which checks the type using RTTI).
Matthieu M.
I agree with Matthieu and smerlin, the Variant types are definitely the way to go. They work extremely well The one thing to be care with is when you extract data from the Variant, you have to ask the object what type is stored in it so that you can store it correctly.
photo_tom
+1  A: 

Everyone saying you can't do this in C++ is missing one obvious solution. This is where you could use a base class, you need to define the commonly used interface there, and then all the derived classes are whatever types you need. Put it in a smart pointer appropriate for a container and there you go. You may have to use dynamic type inference if you can't put enough of the interface in the base class, which is always frowned upon because it's ugly, but it's there for a reason. And dynamically allocating your types probably isn't the most efficient thing, but as always, it depends on what you're using it for.

paul
The data types the OP mentions are built-in, and not part of any class. It would be necessary to wrap the built-ins into classes, with virtual members, and pass the behavior through. It could be done, but it really, really isn't pretty, and there's got to be a better way to handle the OP's real problem.
David Thornley
+1  A: 

I think you are really looking for a dynamically-typed language. Embed an interpreter if you must stick with C++!

Or you could implement something akin to the component model using interfaces to work with wrapped data. Start with the cosmic base class - IObject, then implement interfaces for IInteger, IDouble, IString, etc. The objects themselves would then get created by a factory.

Or you could just use void buffers with a factory... That's the age-old way of avoiding static typing in C/C++ (without the use of inheritance-based polymorphism). Then sprinkle in generous amounts of reinterpret_cast.

Jeremy Brown
+1  A: 

Visual Basic's 'Variant' data type is what you are talking about. It can hold anything, primary data types, arrays, objects etc.

"The Collection class in OLE Automation can store items of different data types. Since the data type of these items cannot be known at compile time, the methods to add items to and retrieve items from a collection use variants. If in Visual Basic the For Each construct is used, the iterator variable must be of object type, or a variant." -- from http://en.wikipedia.org/wiki/Variant_type

The above page gives some insights on how variants are used and it shows how OLE is used in C++ for dealing with variants.

Abhijeet Pathak
+1  A: 

The closest you can get is with templates:

template<int i> class Data { };
template<> class Data<0> { typedef char type; }
template<> class Data<1> { typedef unsigned char type; }
template<> class Data<2 { typedef short type; }
template<> class Data<3> { typedef int type; }
Data<3>::Type x;

If you need something a lot more complex, Boost has a C++-Python bridge.

MSalters
This has to be resolved at compile time, not at runtime. The question specifically says that the type is not known at compile time but rather at runtime, so this would not be a solution.
David Rodríguez - dribeas
+1  A: 

In your simple example, there would be little benefit in not simply using the widest type in the list as a generic container and casting to the smaller types when necessary (or even relying on implicit casts).

You could get elaborate with unions, classes, polymorphism, RTTI, Boost variants etc, but merely for a list of different width integers it is hardly worth the effort.

It seems to me you have a perceived problem for which you have invented an impractical solution for which you are now asking for help. You'd probably be far better off describing your original problem rather than making your solution the problem!

Clifford
+1  A: 

Also, don't forget that all the functions that must operate on this mysterious data type. Most functions are designed to use only one type, such as addition. The functions are overloaded to handle additional types.

How do you know at run-time what the variable type is?

Thomas Matthews