Sum types can actually be implemented quite effectively using X-macros in both C and C++. In fact, I feel like they're simpler and more intuitive than this variant stuff.
Edit: Let's use the same example.
#define SETTINGS \
X(string, str) \
X(int, num) \
X(bool, b)
struct Setting {
union {
#define X(type, name) type name;
SETTINGS
#undef X
};
enum Type {
#define X(type, ...) t_ ## type,
SETTINGS
#undef X
};
Type tag;
};
Printing settings like in the example becomes this: void printSettings(const Setting& s) {
switch(s.tag) {
case t_string: printf("A string: %s\n", s.str.c_str()); break;
case t_int: printf("An integer: %d\n", s.num); break;
case t_bool: printf("A boolean: %d\n", s.b); break;
}
}
We can also load more things into the x-macro, so it's possible to define the switch cases above just like in the structure definition. We could add a third parameter called full_name: void printSettings(const Setting& s) {
switch(s.tag) {
#define X(type, name, full_name) \
case t_ ## type: std::cout << "A " full_name ":" << s.name << "\n";
#undef X
}
}
Disclaimer: I have not compiled or run any of this code.