boost::blank
Boost variant also supports a special type boost::blank
which it treats as a designated empty state if it is one of the value-types.
This allows it to avoid making some of its dynamic allocations -- it behaves
more like std::variant
then.
This is potentially useful for strict_variant
also. It would be nice also if we can be nothrow_move_constructible
in this scenario, even when recursive_wrapper
are used.
constexpr
support
constexpr
support is somewhat
harder to do well at C++11 standard compared to at C++14. And since constexpr
computations cannot make dynamic
allocations, it's not consistent with recursive_wrapper
which is an essential component of easy_variant
.
Any constexpr
usage would be
somewhat orthogonal to the bulk of the development work so far.
It could be added in the future, but for now we simply use placement-new
in our storage and there is no constexpr
support. We could use a more sophisticated storage object, like the recursive
union used in eggs::variant
, without changing the existing
code much. But again, at C++11 standard, it's much harder to do something
useful within a visitor than it is at C++14, so it's not all that attractive.
If you need this, you might want to take a good look at eggs::variant
.
Patches are welcome!
allocator
support
Since recursive_wrapper
makes
dynamic allocations on behalf of the variant, a quite natural refinement
would be to allow custom allocators to be used with the wrapper.
I'm leery of adding the allocator as a template parameter to variant
itself, since it will complicate
usage significantly, and no one else does this.
However, a decent compromise is to support only stateless allocators, and
to pass these as a second template parameter to recursive_wrapper
.
Users can make their own version of template alias easy_variant
using their custom allcators, which would still be quite ergonomic.
One way to mitigate the costs of using recursive_wrapper
in the variant would be if it were possible to "take ownership"
of the dynamic allocation from the variant. Basically the idea would be to
have some kind of "destructive visit" that consumes that variant
and passes the stored value to the visitor, putting it in a std::unique_ptr
if it was held in a recursive_wrapper
.
This is sort of a riff on the "destructive move" proposal:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4158.pdf
noexcept
annotations of variant
when using recursive_wrapper
?
One of the basic design ideas here is to use recursive_wrapper
when a type has a throwing move.
However, this has the potential to reduce the quality of our noexcept
annotations in certain situations.
The reason is that, recursive_wrapper
is supposed to work also when the type is incomplete -- in that case the
traits that determine whether special member functions of the variant throw,
basically have to assume that they might, since we can't check the actual
type.
In cases when the type is complete, we could
introduce a different wrapper, say, heap_wrapper
or something, which would be the same, but we would be able to interrogate
the type to determine situations in which it throws.
Now, usually you would only use heap_wrapper
when the type has a throwing move, and in that case, it likely also has a
throwing copy. So not much is likely to be gained by heap_wrapper
here.
It would be nice if, when recursive_wrapper
is used with a type which is incomplete, but doesn't actually throw, we can
actually deduce that fact. But as far as I know this isn't feasible -- the
noexcept
annotations on the
variant
special member functions
must be complete at the point of instantiation of the variant. So we have
to assume the worst when the user uses recursive_wrapper
,
so far as I know.
std::reference_wrapper
?
The boost::variant
does this, but it doesn't seem
all that useful, and would introduce more complex rules for safety.
std::array
?
It seems simpler to just explicitly forbid arrays, but I didn't do this yet either.
Note that actually, iiuc both references and arrays are forbidden in C++17
std::variant
spec.