2017-06-06 11:15 GMT+02:00 Niall Douglas via Boost
I hate with a passion any possibility of a variant changing its state without me explicitly telling it to do so. The only tolerable state a variant should ever choose on its own is empty/valueless.
I repeat my suggestion that for variant2:
1. If at least all types minus one have nothrow move construction, you get the strongest possible never empty never change guarantee.
2. If the user is dumb enough to supply more than one type with a throwing move constructor, they get the current C++ 17 variant valueless by exception semantics i.e. go valueless if changing state threw an exception and the previous state threw an exception on attempt to restore.
3. We thus never double storage.
4. And we never, EVER change state silently to something the user did not explicitly ask for.
I would recommend not mixing the design discussion of `variant2` with the design considerations of `outcome`. `outcome` has its own design constraints: it is natural to have only one type with a potentially throwing move constructor. In contrast, `variant2
` cannot make any assumptions or guesses about `Ts...`, so it may need different implementation of the assignment. I am not mixing the design discussion. I am talking about variant2 only. I am proposing the above mix of strong never-empty never-change guarantees when the user supplies a reasonable set of types. So:
1. If all but one of the types has a nothrow move constructor, you get the strong never-empty never-change guarantee.
2. If more than one of the types has a throwing move constructor, assignment still moves old state onto the stack before attempting to set new state. If, *and only if*, **both** the move of the new state throws and the attempt to restore the old state ALSO throws, then and only then do we enter valueless-by-exception state.
My view here is that C++ 17 std::variant already has valueless_by_exception(). My proposal is that it becomes a very rare situation indeed to ever occur, and guaranteed not to occur if the types supplied meet the conditions requested.
End user code can test if the never empty guarantee is in place using 'if constexpr(!variant.valueless_by_exception()) ...' because bool valueless_by_exception() would become constexpr false in the implementation with the strong never empty guarantee.
You are basically saying: provide the implementation that gives me strong guarantee when I meet condition X. ("X" being up to one type with potentially throwing move constructor). Your expectation is reasonable, but (I think) it is incompatible with other peoples' expectation: provide implementation that gives me never-empty guarantee when I meet condition Y. ("Y" in that case means I have a type with nothrow default constructor.) I do not think both expectations can be satisfied in one implementation. Regards, &rzej;