Niall Douglas wrote:
double_buffered_variant, really means "give me strong exception safety. I don't care about the cost."
Not quite. It means "I don't trust that somebody won't mess up this variant during code maintenance in the next decade".
Your reformulation aside, "give me the strong guarantee" is exactly what it means, and double buffering is only means to that end and insufficient in itself. A strong guarantee variant must never delegate to the assignment operator of the contained type; it has to destroy and recreate even when the types match. I have argued for this behavior (for std::variant and std::optional) in the past. Aside from delivering the strong guarantee, it can also be used to make a non-assignable type assignable by wrapping it in a variant<> or optional<>. But there's too much opposition and it's never going to be accepted for std::variant or std::optional. The strong guarantee is somewhat of an annoyance. It's almost never needed, and it doesn't compose. If you have two types T and U, which offer the basic guarantee on assignment, so does struct { T t; U u; }. And if they offer the noexcept guarantee on assignment, so does the struct. But if they offer the strong guarantee on assignment, the struct doesn't, and there's no way to make it so (using only the provided strong assignment; if you have noexcept swap, you can, but that's because it's noexcept, a strong swap would similarly be useless). So the strong guarantee is almost always the wrong thing to provide. You want basic for the copy assignment, and noexcept for the move assignment. And people who argue against strong for variant<> have a point.