Subject: Re: [boost] [outcome] Possible extensions/changes to std::experimental::expected
From: Gavin Lambert (gavinl_at_[hidden])
Date: 2017-05-29 22:59:43


On 30/05/2017 03:07, Niall Douglas wrote:
>> Sorry, I probably should have said "since *I assume* outcome<error_code>
>> is legal".
>>
>> I can imagine some scenarios where that might be useful (perhaps as part
>> of some error translation code which wants to return a modified value
>> but can also fail) but I suppose that would complicate the constructors
>> a bit so I can understand why it'd be disallowed, and it should be rare
>> enough not to really bite anyone.
>>
>> (Although tagged constructors to resolve that ambiguity wouldn't be an
>> issue if you could only create an errored outcome with a helper like
>> make_unexpected...)
>
> It's disallowed purely to avoid SFINAE on constructors and thus improve
> compile times.

That's why I mentioned tagged constructors. No SFINAE needed.
Something like:

template<typename T>
class result
{
public:
     struct error_tag {};

     outcome(const T& val) { set_value(val); }
     outcome(error_code err, error_tag) { set_error(err); }
     //...
};

template<typename T>
result<T> make_error(error_code err)
{
     return result<T>(err, result<T>::error_tag());
}

You could even make the error_tag constructor private and make_error a
friend to ensure that make_error is the only possible way to produce an
errored result. (Or keep the constructor public but make error_tag
private; same effect.)

With this setup, there is no ambiguity when T is error_code -- user code
with "return err" will return the error code as the value, and with
"return make_error(err)" will return it as an error.

I'm not sure I would actually *recommend* this design, I'm just pointing
out that it's possible and removes the ambiguity without any SFINAE.