在这个例子中,std :: variant如何成为valueless_by_exception?

NoS*_*tAl 4 c++ exception variant c++17

这个例子的灵感来自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";   
}
Run Code Online (Sandbox Code Playgroud)

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

虚假,真实

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

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

Tar*_*ama 5

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

template <size_t I, class... Args>
std::variant_alternative_t<I, variant>& emplace(Args&&... args);
Run Code Online (Sandbox Code Playgroud)

它需要一组转发参考.这意味着,从转换操作者Sint评价函数的参数时,不叫; 它被称为体内emplace.由于尝试构建int到位就会失败,因此异常变得毫无价值.

也许有可能实现variant这样的:对于简单的可移动类型,在尝试构建之前保存旧值,然后在失败时恢复,但是我不确定它是否适合类型的各种限制标准给出的实施.

  • Boost有永不空洞的保证......在这种情况下,我相信`boost :: variant`会保存`float`的旧值,因为它可以不被复制/移回.在极少数情况下,无法将任何值恢复为"noexcept",它们使用堆分配和"双缓冲".`valueless_by_exception`被选为`std :: variant`而不是由于性能原因而永远为空的保证,因为`boost :: variant`的失败模式可能非常令人惊讶. (2认同)