On 3/03/2019 07:25, Niall Douglas wrote:
I just don't get why variant2 would set a state of C when it had state A, and setting state B failed. It should have spotted the lack of common noexcept move, employed double buffers, and alternated between them such that state A is untouched should setting state B fail.
If it's going to do weirdness like setting state C out of the blue, then better dispose entirely any double buffered implementation as not adding value.
While I agree that switching to an apparently unrelated state is surprising, it could be anticipated and "solved" by always using monostate as the first type where the types might throw on move. (And perhaps variant could issue a warning or error if you try to do otherwise?) It seems reasonable to require a monostate state to exist unless using types that can guarantee that it is never needed. And with it "in their face" in the type declaration, consumers of the variant should be less likely to forget about handling it, which is one of the problems with valueless_by_exception. (On a peripherally related note, why did variant introduce monostate instead of reusing nullopt_t?) I find it a lot more common that people writing move constructors/assignment forget to declare it noexcept than it actually being exception-prone, so having more diagnostics ("if you really meant to do that, add monostate") rather than silently degrading performance seems like a good thing.