4 ms·
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 vari
by any1 9y ago
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.
- jcelerier 9y agothere's absolutely zero compile time safety in your code. If someone copy-pastes for instance case t_int: printf("An integer: %d\n", s.num); break; case t_bool: printf("An boolean: %d\n", s.num); break; it will just break at runtime, unlike std::variant which prevents this at compile time
- any1 9y agoYes, which is why I would always use the second example for the print function. Edit: In fact it is possible to handle the cases explicitly while enforcing types by having the X-macros call functions in the switch/case and declaring prototypes via the macros: #define X(type, ...) void printSettings_ ## name(type); SETTINGS #undef X void printSettings(const Setting& s) { switch(s.tag) { #define X(type, name) \ case t_ ## type: printSettings_ ## name(s.name); break; SETTINGS #undef X } } Then you define printSettings_... and have them do stuff with the data.