
On Fri, Jan 11, 2013 at 5:56 PM, Peter Dimov <lists@pdimov.com> wrote:
Paul Smith wrote:
Even though it's called the "never-empty guarantee", I always thought that variant actually provides a strong exception guarantee (i.e. the variant is not just left unempty, but specifically in the previous state) so it's not directly relevant. Am I wrong?
Yes, I believe you are. The problem is that it's hard to provide the basic guarantee. Here's why. Imagine you are assigning one variant to another, but the contained types do not match. You need to destroy the target type first, then construct a source type into the target variant. This construction can throw. If it does, you have an invalid target, and no way to bring it back into a valid state. Any valid state, not just the original. If the variant did have an implicit empty state, you'd use it, but it doesn't, so you can't.
I'm aware of the difficulity, but I completely repressed the "Enabling Optimizations" section :) You're right.
Anyway, there's no need to outright disallow move in any case. The goal is simply to find a good move target. Automatically assuming that a non-throwing default constructor is a good move target is a heuristic.
It's not a heuristic. It's the actual requirement that makes a type usable for the task. It makes no sense to use another requirement in its place, or let the user fiddle with it.
It is a heuristic. Just because something is no-throw doesn't necessarily mean that it's cheap. But since it's no longer a precedence, it's fine. Still, there's no need to supress move construction in the absence of a no-throw default constructible type. -- Paul Smith