std::variant<int, whatever> v;
// v is zero
and std::variant<int, whatever> v = 0;
And don't want to pay the space and time overhead of wrapping in an std::optional which will use a whole other byte at least for not good reasonThis. monostate's behavior should be captured in the std::optional spec. There's no need to create a new type.
Edit: My point, if not clear, is that the compiler should add the extra bit of code for when an optional is empty automatically, rather than requiring that an optional be defined (it's optional!) unless it is explicitly typed as monostate.
Brevity, I guess? I suppose the most brief way to express absence or presence of value in C++ is a pointer, but I could be tried at the Hague for that take.
None of this is to be facetious, I'm really trying to learn here. I'm not a C++ guy by trade. C and Rust are my day-to-day languages.
std::variant<std::monostate, T, U, V>
Or std::optional<std::variant<T, U, V>>
But then the "none" state is a bit more "special", it's not just one of the options. The sizeof of the type will also probably be a bit bigger, because it has to contain both the bool for the optional, as well as the tag for the variant.The other obvious use is what the article states, that it allows the variant to be default constructed even if none of its members are. Though you can do that with optional as well. It's mostly a matter of style. I mostly avoid std::monostate because the name is so confusing, I really agree with the other users that something like std::unit or std::none would be better.
Ah, okay! So it's serving the same purpose as the "None" in this Rust snippet:
enum Foo {
None, // <-- impl core::Default and return this
T(T),
U(U),
V(V),
}
That makes sense, though it really shows how the legacy of C++'s type system limits stdlib design in the present day. It'd be awfully nice to be able to just write std::variant<void, T, U, V>.Fundamentally, Rust’s enums are a much better way of doing this thing compared to std::variant, but C++ did the best it could without changing the core language. Which arguably they should have done.
The size of an optional<T> is `sizeof T + 1` because it needs a boolean for the set/unset flag.
The size of a variant is… the same, at least, because it needs to store a discriminator integer (apparently both gcc and clang do optimise to a byte when there are less than 256 variants).
Or do you mean adding a monostate to an existing variant rather than wrap that variant into an `optional`? In which case you should fix your example (and provide a version wrapped in an optional) because they’re very confusing.
Current situation: you have
std::variant<int, whatever> x;
you now want to discriminate on whenever x has been initialized explicitly or not, the two cases I posted: // case 1
std::variant<int, whatever> x;
// case 2
std::variant<int, whatever> x = 0;
you have two options:option A: does not needlessly increase sizeof, does not add indirection penalty upon access:
std::variant<std::monostate, int, whatever> x;
option B: needlessly increases sizeof, adds indirection penalty upon access (mostly relevant when compiling in debug mode without inlining if you still want to have a semblance of performance): std::optional<std::variant<int, whatever>> x;