I have to say that I'm with Andrzej on this matter. Mabye I'm blind, but it seems to me that people repeatedly mix up "never empty" and "no error state". Variant2 can still get into an error state, just that that error state is not explicitly named and modeled as part of variant2, but instead, a "regular" state is reused to signal that error: Either monostate or whatever is the first type that has a non throwing default constructor. It is only if neither of those options is available that variant2 falls back to double buffering and does actually avoid ending up in an error state at all. Also, I don't see the problem with valueless_by_exception. Other than nullptr, you don't have to explicitly check for it most of the time (at least not more often than you'd have to check for monostate in variant2). Consider what you can do with a variant: - get: If you are guessing the current type wrong, you get an exception Doesn't matter if the actual type is valueless_by_exception or just an unexpected regular type. - get_if: Again, if you are guessing wrong, you get a nullptr - copy/move: valueless again behaves just like another type - index: Valueless just returns a unique index. The only special thing about it is that it doesn't fall into the regular range between zero and the number of member types. - comparison operators: valueless_by_exception is even more convenient, because you don't have to check first if the left and right hand side are of the same type, but you can still treat it just as any other T if you want. - visit: This is the only case where valueless is really special: You get an exception instead of having to provide an overload for e.g. monostate. Considering how rarely a variant ends up in such a state, throwing an exception is imho the right thing to do most of the time anyway (use an exception to report exceptional errors). But when that is not appropriate, then yes, you have to either check beforehand or catch the exception instead of building the logic into your visitor. Of course I can imagine a scenario, where one or the other approach is simpler, but 99% of the time it really doesn't make a big difference. What I'm trying to say here is not that the design of std::variant is better than boost::variant2, but that they are just two different design choices that may be more or less convenient in a particular scenario, but overall don't make a big difference one way or the other. What I personally do find a bit problematic is that variant2 would be yet another variant type that is not completely compatible to std::variant, without providing significant benefits or a fundamentally different design (e.g. providing strong exception guarantee or dramatically improved compile-time or run-time performance). Mike Dev