A more perfect union.
C++14 | C++17 |
---|---|
struct Stuff
{
union Data {
int i;
double d;
string s; // constructor/destructor???
} data;
enum Type { INT, DOUBLE, STRING } type;
}; |
struct Stuff
{
std::variant<int, double, string> data;
};
|
Usage
C++14 | C++17 |
---|---|
void handleData(int i);
void handleData(double d);
void handleData(string const & s);
//...
switch (stuff.type)
{
case INT:
handleData(stuff.data.i);
break;
case DOUBLE:
handleData(stuff.data.d);
break;
case STRING:
handleData(stuff.data.s);
break;
} |
void handleData(int i);
void handleData(double d);
void handleData(string const & s);
//...
std::visit([](auto const & val) { handleData(val); }, stuff.data);
// can also switch(stuff.data.index())
|
How the above lambda works |
---|
struct ThatLambda
{
void operator()(int const & i) { handleData(i); }
void operator()(double const & d) { handleData(d); }
void operator()(string const & s) { handleData(s); }
};
ThatLambda thatLambda;
std::visit(thatLambda, stuff.data);
|
More Usage
C++17 |
---|
if (holds_alternative<int>(data))
int i = get<int>(data);
// throws if not double:
double d = get<double>(data);
|
C++17 |
---|
std::variant<Foo, Bar> var; // calls Foo()
// (or doesn't compile if no Foo())
Bar bar = makeBar();
var = bar; // calls ~Foo() and Bar(Bar const &)
// (what if Bar(Bar const & b) throws?)
var = Foo(); // calls ~Bar() and move-ctor Foo(Foo &&)
// (what if Foo(Foo && b) throws? - even though moves shouldn't throw)
var = someFoo; // calls Foo::operator=(Foo const &)
std::variant<Foo, std::string> foostr;
foostr = "hello"; // char * isn't Foo or string
// yet foostr holds a std::string |