Le 31/05/2017 à 10:26, Gavin Lambert via Boost a écrit :
I probably should have thought of asking this earlier, but it occurs to me now that my own mental model of how an "outcome"-ish type should act is probably not suited to variant storage at all.
So just out of curiosity I thought I'd ask whether people prefer this sort of interface:
template<typename T> class outcome { public: bool has_value() const { return m_storage.has<T>(); } T& value() { return m_storage.get<T>(); }
bool has_error() const { return m_storage.has
(); } error_code& error() { return m_storage.get (); } bool has_exception() const { return m_storage.has
(); } exception_ptr& exception() { return m_storage.get (); } void set(none_t) { m_storage = none; } void set(const T& val) { m_storage = val; } void set(error_code err) { m_storage = err; } void set(exception_ptr ep) { m_storage = ep; }
private: variant
m_storage; };
Does none_t mean success or failure?
For what I see it means failure as it is not the result of value().
In addition it default construct to none_t.
The mental model for me is
variant
Or this sort of interface:
template<typename T> class outcome { public: bool has_value() const { return !!m_value; } T& value() { ensure(); return m_value.value(); }
//bool has_error() const { return !!m_error; } const error_code& error() const { return m_error; }
//bool has_exception() const { return !!m_exception; } const exception_ptr& exception() const { return m_exception; }
void ensure() const { if (m_exception) { rethrow_exception(m_exception); } if (m_error) { throw system_error(m_error); } }
void set(none_t) { m_value = none; m_error = error_code(); m_exception = nullptr; } void set(const T& val) { m_value = val; m_error = error_code(); m_exception = nullptr; } void set(error_code err) { m_value = none; m_error = err; m_exception = nullptr; } void set(exception_ptr ep) { m_value = none; m_error = ep ? error_code(errc::has_exception) : error_code(); m_exception = ep; }
private: optional<T> m_value; error_code m_error; exception_ptr m_exception; };
I guess you want a variant here. You don't want to store all of them,
isn't it?
I could understand
varaint
(Don't get too hung up on the specifics. This is a sketch, not a real implementation. I've obviously omitted things that a real implementation would need such as more const methods and move support, and construction and assignment rather than using set methods. The focus is on variant vs. non-variant.)
Anyway, the point is that this could actually transport multiple things; in particular as above both an error_code and an exception_ptr; perhaps set(error_code) could construct an exception as well, although I've explained elsewhere why I don't like that option.
Perhaps this could even be exposed even more so that user code could explicitly provide both a value and an error -- think "here's a value, but it was truncated" or "here's the 5 values you asked for, but there's more", both fairly common in system APIs. Or for things like ambiguous matches where you still return the most likely candidate. Or dictionary insertion (duplicate key, but here's the value that's already there). Or many more such examples. (Though obviously in this case value() couldn't call ensure(). But that should make some people happy.)
This corresponds to the status_value [1] model where you store the
reason why you don't have a value or why you have it and an
optional<value>. As described by L. Crowl in [2], there are use cases
for status_value, expected and exceptions.
pair
Also note has_error() and has_exception() don't even need to be provided in this version since you can always call error() and exception() in a boolean context anyway, with the same result. (Or actually a slightly better result than the implementation shown here.)
I don't see why we need to choose.between the narrow and the wide functions yet. First you need to state what is your mental model. The provide the operations.
The obvious downside is that it now uses more storage, which might hinder some inlining cases.
I'm not sure of this possible missing optimization. Best, Vicente [1] P0262R1 A Class for Status and Optional Value http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0262r1.html [2] P0157R0 Handling Disappointment in C++ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0157r0.html