2018-01-22 15:53 GMT+01:00 Niall Douglas via Boost
My recommendation would be not to provide comparison operators if either `T` or `EC` does not provide them.
Agreed. Logged to https://github.com/ned14/outcome/issues/107
The trick with catch-reswap-rethrow assumes that `T` is more likely to throw while swapping/moving than `EC`, but it might be quite the opposite. Also, it is possible that while reswapping, another exception will be thrown. In general, you cannot guarantee the roll-back, so maybe it would be cleaner for everyone if you just declared that upon throw from swap, one cannot rely on the state of `result`: it should be reset or destroyed.
So, don't bother attempting to restore a valid state at all?
To me, restoring makes sense if you can guarantee that it succeeds. Maybe if you do it only if `EC` is nothrow-swappable.
Does everybody else agree?
Another problem is that in the noexcept() clause you are mentioning is_nothrow_swappable
and is_nothrow_swappable , but in the implementation you might be using move constructors rather than swaps. This means that for types that do not throw in swap but throw in move constructor (like std::list), a throw from move constructor will cause a call to `std::terminate`. See live example here: https://wandbox.org/permlink/8jIyb0fx7U72cZSt Surely if std::is_nothrow_swappable tells lies, it is only right that that equals std::terminate? In other words, if the STL traits tell me that `swap(A, B)` does not throw, and then it throws because it's implemented with move constructors, that's surely not my problem?
No, no. This happens not inside STL, but inside `result`: https://github.com/ned14/boost-outcome/blob/master/include/boost/outcome/det... Inside the implementation of function `value_storage_nontrivial::swap` you are using move construction in certain cases. And this move constructor of `T` can potentially throw and may be declared `noexcept(false)`, but you will not see it if you are only querying for noexcept swap on `T`. Regards, &rzej;