Store different types of variables in one entity in C++

Viewed 140

I am relatively new to C++, so trying to find the best way to store different types of values under one entity. Context is, I have a function which returns a struct and one of the values can be of different types. At any time, only one value will be set. Best case for me would be if I can do something like this:

Union Union1 {
int x;
char y;
double z;
}

executor(Union1 union1) {
  if(union1.x.isSet()) {
    doSomethingUsingX();
  } else if(union1.y.isSet()) {
    doSomethingElseUsingY();
  }
}

I dont think this is possible because c++ unions use same memory space. So is there something I can use?

2 Answers

If you use C++17 or newer, try std::variant. See https://en.cppreference.com/w/cpp/utility/variant

If older than C++17 you can try boost::variant

The variant is a better way to do a union. It also records what kind of thing is stored in it, and you can use std::visit to call a type overloaded function on a variant.

Like this, adapted from the cppreference example:

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

Also this blog post I found online seems to help explain how that works: https://pabloariasal.github.io/2018/06/26/std-variant/

You could use an enum to report the return type:

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