No, no, no! This is terrible!<p>variant_cast is just garbage. It relies on struct layout, and if anything has wider alignment than ptrdiff_t, it's broken.
For example, a double in 32-bit PowerPC has 64-bit alignment but ptrdiff_t is 32 bits, so the pointer is wrong. Maybe x64 you get away with it for most types (not all!), but can you raise your right hand and solemnly swear that you'll never ever want to port to a non-x64 system?<p>Additionally, all the explicit casting means that this has basically no type safety at all. I can a.tag = tag(SomeThree) even though SomeThree is not a member of a's type, and then I will be able to successfully let b = as(&a, SomeThree) and boom! I've just scribbled over memory without so much as a peep from the compiler. What is the of having tagged unions (a TYPE SAFETY FEATURE) if your tagged union implementation is LESS type safe than untagged unions?<p>This last point is actually a bit subtle… accessing the wrong member of a union is probably not what you want to do most of the time, but the language in the C standard is quite clear (see DR #257, language was clarified in C99 but present in earlier versions) and accessing the wrong union member just gives you whatever you stored in a union reinterpreted as whatever you read out of it. But this tagged union implementation lets you access a union member which doesn't even exist.<p>Let's not try to implement new language features on top of C with macros. It never ends well. Either figure out a way to live with a little boilerplate or use a different language, those are the only sane options.
Is there a reason, other than jargon, why this concept is called different names in different languages?<p>Do variants work different than tagged unions or type classes?<p>Some people told me that Haskell is superior in FP because of its type classes. Later I read TypeScript has tagged unions, which looked like type classes to me.<p>Then I looked into Reason and they wrote about variants and I also was reminded of type classes.