开发者

Declaring a data type dynamically in C++

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?


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.


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


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


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.


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.


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.


use union and make your own dynamic class. the pseudocode like:

union all{
    char c;
    unsigned char uc; 
    short s; 
    int i;
}; 

class dynamic{ 
    public:
        char Type; 
        all x; 

        template <class T> 
        dynamic(T y){ 
            int Int;
            char Char;
            unsigned char Uchar;
            short Short;
            if (typeof(y) == typeof(Char)){
                Type = 1;
            }else if (typeof(y) == typeof(Uchar)) {
                Type = 2; 
            }else if (typeof(y) == typeof(Short)) {
                Type = 3;
            }else{
                Type = 4;
            } 

            switch (Type) {
                case 1: x.c = y; break;
                case 2: x.uc = y; break;
                case 3: x.s = y; break ;
                case 4: x.i = y; break ; 
            }
        } 

        auto get() {
            switch(Type) {
                case 1: return x.c; 
                case 2: return x.uc; 
                case 3: return x.s; 
                case 4: retuen x.i; 
            }
        }  

    //also make the operators function you like to use
} ;


however you should avoid using the dynamic type as possible as you can because it is memory inefficient
(in this example, each object of dynamic will takes 5 bytes)

it will also slow down your code (a bit).
if in your example you want to use dynamic type of number variable only to reduce memory usage, you should forget about dynamic and just use the integer as the type (where integer can contain all of char, unsigned char, and short at once).

but if you want to use it because you need a dynamic type between something really different (example between an int and a string or a custom object), then it will be one of your option.


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.


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.


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!


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?


The only way that come to mind now is the old C style where pointer to void was used like:

void *unkown;

Leter on you can assign any object to it like below:

unkown = (void *)new int(4);

If you know the type in the runtime then you may run specified function on such variable like below:

if(type==0) { // int 
    printf("%d\n", * ((int*)unkown) );
} else {
    // other type
}

This way (casting void*) is used for example when malloc [, etc.] function is used.

I'm not saying it is a good practise when c++ is now much more developed. Still agree with persons that saying it is not the best solution for your problem. But maybe after some redesign you may find it helpful.

You may find also interesting auto type since C++11. http://en.cppreference.com/w/cpp/language/auto


I guess this reply would be a few years late. But for people who might happen to view this thread, a possible solution for this would be using variable templates. For example:

template<typename T>
T var;

template<typename T>
T arr[10]; 

int main() {
    int temp;
    var<int> = 2;
    cout << var<int> << ' '; // this would output 2
    var<char> = 'a';
    cout << var<int> << ' '; // var<int> value would be a space character
    cout << var<char> << ' '; // this would output 'a'
    for(int i = 0; i < 10; i++) {
        switch(i % 2) {
            case 0:
                arr<int>[i] = ++temp;
                break;
            case 1:
                arr<char>[i] = 'a' + ++temp;
                break;
    }
    cout << endl;
    for(int i = 0; i < 10; i++) {
        switch(i % 2) {
            case 0:
                cout << arr<int>[i] << ' ';
                break;
            case 1:
                cout << arr<char>[i] << ' ';
                break;
        }
    }
    return 0;
}

The only problem with this, is that you would need to know the variable type of what is currently within the variable(e.g. storing in an integer array what the variable's "id"(the id you would give it), for a specific type). If you do not know or do not have a condition to know what is inside a specific variable or array location, I do not suggest using this.


I try to post it in here, but I had format error. I decided to put a link. Any way you can use (long long) to store addresses because size of address is 8 and size of (long long) also is 8 then it can hold an address.

https://www.flatech.com.au/learning-material/programming/c/object-pointers-to-any-type

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜