#c #unions
#c #объединения
Вопрос:
Я относительно новичок в C , поэтому пытаюсь найти наилучший способ хранения различных типов значений в одной сущности. Контекст заключается в том, что у меня есть функция, которая возвращает структуру, и одно из значений может быть разных типов. В любой момент времени будет установлено только одно значение. Лучшим вариантом для меня было бы, если бы я мог сделать что-то вроде этого:
Union Union1 {
int x;
char y;
double z;
}
executor(Union1 union1) {
if(union1.x.isSet()) {
doSomethingUsingX();
} else if(union1.y.isSet()) {
doSomethingElseUsingY();
}
}
Я не думаю, что это возможно, потому что объединения c используют одинаковое пространство памяти.
Итак, есть ли что-нибудь, что я могу использовать?
Ответ №1:
Если вы используете C 17 или новее, попробуйте std::variant
. Смотрите https://en.cppreference.com/w/cpp/utility/variant
Если вы старше C 17, вы можете попробовать boost::variant
variant
Это лучший способ выполнить объединение. В нем также записывается, что за объект в нем хранится, и вы можете использовать std::visit
для вызова функции с перегруженным типом в variant
.
Вот так, адаптировано из примера cppreference:
#include <iostream>
#include <variant>
#include <vector>
// helper type for the visitor #4
template <class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
// explicit deduction guide (not needed as of C 20)
template <class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
int main() {
std::vector<std::variant<int, char, double>> v;
v.emplace_back(1);
v.emplace_back('c');
v.emplace_back(2.7);
for (const auto amp;x : v) {
std::visit(
overloaded{[](auto arg) { std::cout << "unknown " << arg << 'n'; },
[](int arg) { std::cout << "int " << arg << 'n'; },
[](double arg) { std::cout << "double " << arg << 'n'; },
[](char arg) { std::cout << "char " << arg << 'n'; }},
x);
}
return 0;
}
Также этот пост в блоге, который я нашел в Интернете, кажется, помогает объяснить, как это работает:
https://pabloariasal.github.io/2018/06/26/std-variant /
Ответ №2:
Вы могли бы использовать перечисление для сообщения возвращаемого типа:
typedef enum
{
x,
y,
z
}returnType;
typedef struct
{
returnType rt;
union
{
int x;
char y;
double z;
};
}myStruct;
//...
myStruct AFunctionWithMyStructReturnType(int arg)
{
myStruct ms;
if(arg == 0)
{
ms.rt = returnType.x;
ms.val = 10000;
}
else if(arg == 1)
{
ms.rt = returnType.y;
ms.val = 200;
}
else
{
ms.rt = returnType.z;
ms.val = 3.14;
}
return ms;
}
//...
myStruct S = AFunctionWithMyStructReturnType(arg);
switch(S.rt)
{
case returnType.x:
processX(S.val);
break;
case returnType.y:
processY(S.val);
break;
case returnType.z:
processZ(S.val);
break;
}
Комментарии:
1. Проблема с объединением в том, что вы не можете хранить в них типы STL, подобные
std::vector
, поскольку нет способа узнать, как уничтожить такие объекты.std::variant
упоминание в другом ответе — лучший выбор, если вы используете C 17/