在这个例子中,std::variant 是如何变成 valueless_by_exception 的?

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

这是受 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";   
}

对于一个编译器,我试过它输出

false, true

意味着 emplace 导致变体变得毫无价值

我不明白这是怎么发生的。 特别是我不明白为什么 emplace 被调用,我希望程序甚至不会调用它,因为从 S 到 int 参数的转换会抛出。

注意相关 std::variant::emplace 重载的签名:

template <size_t I, class... Args>
std::variant_alternative_t<I, variant>& emplace(Args&&... args);

它需要一组转发引用。这意味着在评估函数参数时不会调用从 Sint 的转换运算符;它在 emplace 的正文中被调用。由于尝试就地构建 int 会失败,因此变体因异常而变得毫无价值。

也许可以实现 variant 这样对于普通的可移动类型,在尝试就地构造之前保存旧值,然后在失败时恢复,但我不确定是否它符合标准对类型实现的各种限制。