Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does std::variant becomes valueless_by_exception in this example?

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.

like image 867
NoSenseEtAl Avatar asked Nov 24 '17 10:11

NoSenseEtAl


1 Answers

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.

like image 192
TartanLlama Avatar answered Oct 07 '22 03:10

TartanLlama