Объявление динамического типа данных в С++

Я хочу иметь возможность сделать следующее:

У меня есть массив строк, содержащих типы данных:

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

Затем позже я хотел бы создать переменную одного из типов данных во время выполнения. Я не буду знать во время компиляции, какой должен быть правильный тип данных.

Так, например, если во время выполнения я определил переменную x, которая должна быть типа int:

DataTypeValues[3] x = 100;

Очевидно, что это не сработает, так как я могу сделать что-то вроде этого?

Ответ 1

Простой ответ заключается в том, что вы не можете - типы должны быть известны во время компиляции в С++. Вы можете делать что-то вроде этого, используя boost:: any или union, но это будет не так.

Ответ 2

вам нужно будет использовать союзы для достижения чего-то подобного, но обработка объединений - очень сложный вопрос, поэтому вы должны выбрать класс контейнера, который обертывает логику объединения за интерфейсом, например Boost.Variant или Qts QVariant

Ответ 3

Вы не можете. Такое метапрограммирование во время выполнения не поддерживается в С++.

Ответ 4

Все, кто говорит, что не можете сделать это на С++, не хватает одного очевидного решения. Здесь вы можете использовать базовый класс, вам нужно определить там обычно используемый интерфейс, а затем все производные классы будут любыми типами, которые вам нужны. Поместите его в умный указатель, подходящий для контейнера, и там вы идете. Возможно, вам придется использовать вывод динамического типа, если вы не можете поместить достаточное количество интерфейса в базовый класс, который всегда нахмурился, потому что он уродлив, но он там по какой-то причине. И динамическое распределение ваших типов, вероятно, не самая эффективная вещь, но, как всегда, это зависит от того, для чего вы ее используете.

Ответ 5

Единственное, что вы можете сделать, это вручную перебирать типы и сравнивать каждый из них. Здесь также можно использовать объект factory здесь, но это будет связано с кучей.

Ответ 6

Я думаю, что вы действительно ищете динамически типизированный язык. Вставьте интерпретатор, если вы должны придерживаться С++!

Или вы можете реализовать что-то похожее на модель компонента, используя интерфейсы для работы с обернутыми данными. Начните с космического базового класса - IObject, затем реализуйте интерфейсы для IInteger, IDouble, IString и т.д. Затем сами объекты создаются с помощью factory.

Или вы могли бы просто использовать void-буферы с помощью factory... Это вековой способ избежать статической типизации в C/С++ (без использования полиморфизма на основе наследования). Затем посыпать щедрым количеством reinterpret_cast.

Ответ 7

Тип данных Visual Basic "Вариант" - это то, о чем вы говорите. Он может содержать все, первичные типы данных, массивы, объекты и т.д.

"Класс Collection в OLE Automation может хранить элементы разных типов данных. Поскольку тип данных этих элементов не может быть известен во время компиляции, методы для добавления элементов в элементы из вариантов использования коллекции и извлечения из них. Если в Visual Используется базовая конструкция" Для каждой ", переменная итератора должна быть типа объекта или варианта". - от http://en.wikipedia.org/wiki/Variant_type

На приведенной выше странице дается некоторое представление о том, как используются варианты, и показывает, как OLE используется в С++ для работы с вариантами.

Ответ 8

Самое близкое, что вы можете получить, это с шаблонами:

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;

Если вам нужно что-то более сложное, Boost имеет мост С++ - Python.

Ответ 9

В вашем простом примере будет мало пользы в том, что вы не просто используете самый широкий тип в списке в качестве универсального контейнера и при необходимости накладываете меньшие типы (или даже полагаетесь на неявные отбрасывания).

Вы можете получить подробные сведения о союзах, классах, полиморфизме, RTTI, вариантах Boost и т.д., но просто для списка различных целых чисел ширины вряд ли стоит усилий.

Мне кажется, у вас есть воспринимаемая проблема, для которой вы изобрели непрактичное решение, о котором вы сейчас просите о помощи. Вероятно, вам будет гораздо лучше описать вашу исходную проблему, а не решить проблему.

Ответ 10

Кроме того, не забывайте, что все функции, которые должны работать над этим таинственным типом данных. Большинство функций предназначены для использования только одного типа, например добавления. Функции перегружены для обработки дополнительных типов.

Как вы знаете во время выполнения, какой тип переменной?

Ответ 11

Единственный способ, который приходит в голову сейчас, - это старый стиль C, в котором использовался указатель на void:

void *unkown;

Leter вы можете назначить для него любой объект, как показано ниже:

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

Если вы знаете тип во время выполнения, вы можете запустить указанную функцию для такой переменной, как показано ниже:

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

Этот способ (casting void *) используется, например, когда используется функция malloc [и т.д.].

Я не говорю, что это хорошая практика, когда С++ теперь намного более развит. Все еще согласны с людьми, говорящими, что это не лучшее решение вашей проблемы. Но, возможно, после некоторой редизайна вы можете найти это полезным.

Вы также можете найти интересный авто-тип с С++ 11. http://en.cppreference.com/w/cpp/language/auto

Ответ 12

Я думаю, этот ответ будет несколько лет позже. Но для людей, которые могли бы просмотреть этот поток, возможным решением для этого будет использование переменных шаблонов. Например:

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;
}

Единственная проблема с этим заключается в том, что вам нужно будет узнать тип переменной того, что находится в данный момент в переменной (например, сохранение в массиве целого числа, что переменная "id" (идентификатор, которую вы ей дали), для конкретный тип). Если вы не знаете или не знаете, что находится внутри определенной переменной или местоположения массива, я не предлагаю использовать это.

Ответ 13

используйте union и создайте свой собственный динамический класс. псевдокод, такой как:

union all{
char c;
unsigned char uc; 
short s; 
int i;
}; 
class dynamic{ 
public:
char Type; 
all x; 
template <class T> 
dynamic(char type_,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; 
}
}  
//make also the operators function you like
} ;

однако следует избегать использования динамического типа, насколько это возможно, потому что он неэффективен
(в этом примере каждый динамический объект будет занимать 5 байтов)



это также замедлит ваш код (немного).
если в вашем примере вы хотите использовать динамический тип числовой переменной только для уменьшения использования памяти, вам следует забыть о динамическом и просто использовать целое число в качестве типа (где целое число может содержать сразу все символы char, unsigned char и short).

но если вы хотите использовать его, потому что вам нужен динамический тип между чем-то действительно другим (например, между int и строкой или пользовательским объектом), тогда это будет один из ваших вариантов.