I believe the concern is not whether it's possible to permit void here, but whether it's the right approach to permit void here. 

It's a little unclear as to whether std::expected should act as:

- "return the expected value" (here it would be wrong to permit void as void has no values; instead an explicit unit type would make more sense); or
- "return whatever the function is expected to return" (here it would be correct to permit void; if the function would have returned no value, than it would be expected to return no value)

But given what the paper briefly mentions, it sounds like the latter case was the intention.

Both have implications on generic code; the former allows some .ok() function (or similar) to be called and return a value, whilst the latter allows decltype(auto) functionality to cleanly work.

On Sun, 11 Oct 2020, 7:11 pm Dmitry Dmitry via Std-Proposals, <std-proposals@lists.isocpp.org> wrote:
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.

On Sun, Oct 4, 2020 at 10:21 PM Emile Cormier via Std-Proposals <std-proposals@lists.isocpp.org> 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@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals


--
Dmitry
Sent from gmail
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals