C++ Logo

std-proposals

Advanced search

Re: P0323 std::expected - void value type?

From: Dmitry Dmitry <dimanne_at_[hidden]>
Date: Sun, 11 Oct 2020 19:10:09 +0100
>
> As I understand it, expected is supposed to be a "vocabulary type" similar
> to std::optional, or std::variant, yet the latter two don't permit void as
> one of their contained types (as far as I know).


If this is the main problem, then partial specialisation of your expected<>
for void can solve the issue. You can have a look at what I mean in my
implementation of Result<Ok, Err> here
<https://github.com/DimanNe/result/blob/master/src/result.h>.

On Sun, Oct 4, 2020 at 10:21 PM Emile Cormier via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> Hi Everyone. This is my first time posting to this group, so please be
> gentle. :-)
>
> I'm in need of a value-or-error mechanism for a C++11 library I'm working
> on, where I don't want to impose exceptions to the client. Having completed
> a toy "result<T, E>" implementation inspired by std::expected, I decided to
> implement a complete C++11-ized version of the P0323R9 proposal.
>
> I am questioning the rationale of allowing void as a value type for
> std::expected. As I understand it, expected is supposed to be a "vocabulary
> type" similar to std::optional, or std::variant, yet the latter two don't
> permit void as one of their contained types (as far as I know).
>
> The spec for std::expected is currently very complex with constraints on
> overloads. expected(const expected<U, G>& rhs) in particular is quite scary
> and makes me wonder if it can slow down compilations times. Not having to
> worry about the T=void case would simplify things.
>
> If a user wants to use std::expected to indicate a success-or-failure
> result (with no value), they could simply use something like std::monostate
> as the value type. What I did in my toy result<T,E> implementation is
> provide an empty success_t tag type that can be used when there is no
> meaningful value to return. For example:
>
> struct success_t
> {
> constexpr success_t() = default;
> constexpr bool operator==(success_t) const {return true;}
> constexpr bool operator!=(success_t) const {return false;}
> };
> inline constexpr success_t successful;
>
> result<success_t, std::error_code> write(const std::string& str)
> {
> if (writeToDeviceWorks(str))
> return successful;
> else
> return
> with_failure(make_error_code(std::errc::device_or_resource_busy));
> // with_failure is my equivalent of unexpected(), where I don't
> have the
> // luxury of CTAD in C++11.
> }
>
> int main()
> {
> auto res = write("foo");
> if (res == successful)
> std::cout << "Yay!\n";
> else
> std::cerr << "Oh no: " << res.error() << "\n";
> }
>
> The "successful" object has the benefit that it's quite readable when used
> on the RHS of operator==, as shown above.
>
> The one benefit of allowing T=void I can see is that a std::expected<void,
> E> specialization can get rid of its union storage and directly store
> error_type. Is this the rationale for allowing std::expected<void, E>?
>
> Cheers,
> Emile Cormier
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>


-- 
Dmitry
*Sent from gmail*

Received on 2020-10-11 13:10:38