Реализация стека с использованием массива для поддержки элементов другого типа данных

Как реализовать стек, используя массив, который поддерживает элементы разного типа.
например Он должен работать с символами, целыми числами, числами с плавающей запятой и двойными числами.

Я реализовал это с помощью void указатели. Ниже C реализация:

void push( void** stack, int* top, void* data, size_t size )
{
unsigned i;
++*top;

stack[*top] = malloc( size );

for( i = 0; i < size; ++i )
( (char*)stack[*top] )[i] = ( (char*)data )[i];

}

int main()
{
void* stack[10];
int top = -1, data = 10;
char ch = 'a';

push( stack, &top, (void*)&data, sizeof( int ) );

push( stack, &top, (void*)&ch, sizeof( char ) );

printf( "%d ", *(int*)stack[0] );
printf( "%c ", *(char*)stack[1] );

return 0;
}

Код работает отлично для меня.

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

Существует ли способ реализовать его, не зная предварительной информации о типе данных, с которыми нужно работать? [Я знаю, что это невозможно в C, можем ли мы сделать это в C ++, если да, то как? ]?

1

Решение

Если я понимаю ваше требование, вы можете использовать boost::any чтобы достичь этого в C ++.

#include <boost/any.hpp>
#include <vector>

class AnyStack {
std::vector<boost::any> vec;
public:
template <class T> void push (const T &e) {
boost::any v = e;
vec.push_back(v);
}
class Proxy {
friend class AnyStack;
std::vector<boost::any> &vec;
Proxy(std::vector<boost::any> &v) : vec(v) {}
public:
template <typename T> operator T () {
boost::any v = vec.back();
vec.pop_back();
return boost::any_cast<T>(v);
}
};
Proxy pop () { return Proxy(vec); }
boost::any top () { return vec.back(); }
};

Как предлагали другие, вы можете использовать RTTI для определения типа элемента в стеке. В приведенном ниже примере демонстрируется процедура вывода, которая делает это.

#include <iostream>
#include <string>

std::ostream & operator << (std::ostream &os, const boost::any &a) {
if (a.type() == typeid(char)) {
return os << boost::any_cast<char>(a);
}
if (a.type() == typeid(int)) {
return os << boost::any_cast<int>(a);
}
if (a.type() == typeid(float)) {
return os << boost::any_cast<float>(a);
}
if (a.type() == typeid(double)) {
return os << boost::any_cast<double>(a);
}
if (a.type() == typeid(std::string)) {
return os << boost::any_cast<std::string>(a);
}
}

int main () {
AnyStack a;
a.push(3);
std::cout << a.top() << std::endl;
a.push(std::string("hello"));
std::cout << a.top() << std::endl;
return 0;
}
0

Другие решения

Это может быть сделано в C. Сначала вам нужно перечисление, описывающее содержащийся тип

typedef enum {TYPE_INT, TYPE_CHAR, TYPE_STRING, ... } contained_type_t;

Тогда поместите все в структуру

typedef struct {
contained_type_t contained_type;
union {
int int_value;
char char_value;
void* pointer_value;
... and so on ...
} data;
};

Вы могли бы взглянуть на GObject модель и ее использование в GLib, реализация общий списки, которые можно смешивать типы Интересно.

3

По вопросам рекламы [email protected]