this is example inspired by example from cppreference
struct S {
operator int() { throw 42; }
};
int main(){
variant<float, int> v{12.f}; // OK
cout << std::boolalpha << v.valueless_by_exception() << "\n";
try{
v.emplace<1>(S()); // v may be valueless
}
catch(...){
}
cout << std::boolalpha << v.valueless_by_exception() << "\n";
}
For one compiler I tried it outputs
false, true
meaning that emplace
caused the variant to become valueless
What I do not understand is how this happened.
In particular I do not understand why emplace
is called at all, I would expect the program to not even call it since conversion from S to int argument throws.
Note the signature for the relevant std::variant::emplace
overload:
template <size_t I, class... Args>
std::variant_alternative_t<I, variant>& emplace(Args&&... args);
It takes a pack of forwarding references. This means that the conversion operator from S
to int
is not called when evaluating the function arguments; it's called inside the body of emplace
. Since trying to construct the int
in place would then fail, the variant is made valueless by exception.
It could perhaps be possible to implement variant
such that for trivially movable types, the old value is saved before in place construction is attempted, and then restored if it failed, but I'm not sure if it fits in with the various restrictions on the type's implementation given by the standard.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With