On Sat, Mar 2, 2019 at 1:20 PM Peter Dimov via Boost <boost@lists.boost.org> wrote:
Niall Douglas wrote:
It so happens that the strong guarantee is unachievable with variant (without too much double buffering.) You can either have basic, or noexcept.
You surprise me, given this is a design capable of double buffering.
For a variant2<A, B>, where both A and B have throwing move constructors and assignment, surely if the variant has state A in buffer1, setting it to state B would use buffer2. If B throws during move, we simply don't change the currently selected buffer to buffer2. The variant's A state remains untouched i.e. strong guarantee.
I guess you haven't written out anywhere how and when the double buffering comes into play.
That is actually the one thing I have written, twice, once in the README and one in the Overview section of the documentation. :-)
"To avoid going into a valueless-by-exception state, this implementation falls back to using double storage unless
* one of the alternatives is the type monostate, * one of the alternatives has a nonthrowing default constructor, or * all the contained types are nothrow move constructible."
So, yes, variant<A, B> will be double-buffered, but variant<monostate, A, B> and variant<int, A, B> won't be.
For variant<int, short>, can I assign a T that has an operator int()? Is assignment templatized? What happens with struct Bad { operator int() { throw false; } }; variant<int, short> v = (short)10; v = Bad();