Подтвердить что ты не робот

Как я могу хранить объекты разных типов в контейнере С++?

Есть ли контейнер С++, который я мог бы использовать или строить, который может содержать, скажем, типы int и string и double? Проблема, с которой я сталкиваюсь, заключается в том, что всякий раз, когда я пытаюсь заполнить, скажем, карту, вектор или список, скажем, следующим образом:

int x;
string y;
double z;

Я ограничен форматом:

list<int> mycountainer;
vector<string> mycontainer;

который заставляет mycontainer состоять только из одного типа.

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

Я бы хотел, чтобы избежать использования Boost, если это вообще возможно - я бы предпочел, если бы был простой способ, которым я мог бы это сделать сам.

[править] Эй, парень, большое спасибо за ваши предложения - я должен объяснить, как я буду использовать этот контейнер, но это немного осложнило, следовательно, (большое) упрощение выше. Я думаю, что лучший вариант здесь - использование Boost. Еще раз спасибо.

4b9b3361

Ответ 1

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

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

Мне любопытно, что вы делаете, что вам нужна такая конструкция.

Ответ 2

Ну, первый вопрос: Почему вы думаете, что вам нужно хранить объекты разных, совершенно несвязанных типов в одном контейнере? Это кажется мне неприятным.

Если бы у меня была такая необходимость, я бы посмотрел на boost::variant или boost::any.

Ответ 3

То, что вы хотите, называется "hetrogenious container". С++ технически не поддерживает их в STL, но Boost делает.

Учитывая это, я думаю, вы найдете свой ответ в этом вопросе: how-do-you-make-a-heterogeneous-boostmap

Ответ 4

Вы можете использовать либо структуры, либо классы, либо std:: pair.

[править]

Для классов и структур:

struct XYZ {
    int x;
    string y;
    double z;
};
std::vector<XYZ> container;

XYZ el;
el.x = 10;
el.y = "asd";
el.z = 1.123;
container.push_back(el);

Для std:: pair:

#include <pair>
typedef std::pair<int, std::pair<string, double> > XYZ;
std::vector<XYZ> container;
container.push_back(std::make_pair(10, std::make_pair("asd", 1111.222)));

Ответ 5

Вы можете использовать структуру, содержащую все три.

struct Data
{
    int intVal;
    std::string stringVal;
    double doubleVal;
};

Тогда вы можете просто объявить list mycontainer<Data> и использовать соответствующее значение, если знаете, что такое тип значения. Если нет, добавьте в структуру добавление поля, в котором указывается, какой из трех типов данных используется.

struct Data
{
    enum DATATYPE { DT_INT, DT_STRING, DT_DOUBLE } type;

    int intVal;
    std::string stringVal;
    double doubleVal;
};

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

Ответ 6

Если у вас есть конечное количество элементов, которые нужно сохранить, поместите их в класс или структуру.

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

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

Если С++ содержит отражение, возможно, будет способ сделать это, но С++ не имеет отражения.

Ответ 7

Простейшим методом является, конечно, определение структуры или класса, в котором есть элементы каждого из типов, которые вы хотите сохранить. Josh answer предлагает Boost.Any, который будет содержать почти все. Если вы хотите ограничить значения только теми типами int, double и std::string, то лучшим выбором будет Boost.Variant.

Если вы просто не хотите использовать Boost, то я предлагаю вам покончить с зависанием и использовать его в любом случае. "Не изобретать здесь" - это саморазрушительная политика. Но если вы не можете использовать Boost, тогда вы можете написать свой собственный вариантный вариант. Андрей Александреску написал серию из трех частей (часть 1, часть 2, часть 3) несколько лет назад, и ее дизайн вдохновил один Boost.