expected revision 11 keeps a typed error beside the success contract
expected carries either a value or a typed error without making failure an empty state. Revision 11 refines the library wording while preserving distinct checked and unchecked access paths.
A parser can need to remember a failure while continuing to examine its input. Returning an integer error code separately from a value makes that relationship a convention. Throwing immediately makes continuation a control-flow decision. A value-or-error object gives the parser another option, allowing it to retain each outcome and decide later which failure determines the result.
The November 16 P0323R11 proposal for std::expected includes a WebKit parsing example with that requirement. Vicente Botet, JF Bastien, and Jonathan Wakely present a vocabulary type containing either an expected value of type T or an error of type E. The proposal is under library wording review, with no claim that every C++ implementation already provides it.
I value a return type that makes an interface's recoverable failure model explicit. C++ can express that relationship without allocating a separate object for every branch, but the surrounding contract still needs care. The caller must know which state it holds before using an accessor whose preconditions require that state.
The error is part of the returned object
expected<T, E> supplements the idea behind optional<T> by recording why the value is absent. It is not simply an optional value with a global error variable somewhere else. The returned object retains the error type chosen by the API, so different functions can describe different failure information directly in their signatures.
The proposal deliberately favors the success case in its construction syntax. A suitable T value can construct a successful object. Constructing the error uses unexpected or the unexpect tag. That distinction is necessary even when T and E happen to be the same type, because the type of the supplied value alone cannot identify its intended role.
For example, the proposed interface can represent a small parsing result as follows:
#include <expected>
enum class digit_error { invalid };
std::expected<int, digit_error> parse_digit(char input)
{
if (input < '0' || input > '9')
return std::unexpected(digit_error::invalid);
return input - '0';
}
This example uses the proposal's standard-library names and requires an implementation supporting them. It returns a value only for the indicated character range. A caller can inspect success before accessing the integer, or retrieve the typed error when the check fails.
The distinction between tagging and content also applies to richer errors. A success-like numeric value inside an error object does not change which alternative the expected holds. The object's discriminator establishes that state. An application should not assume that an error payload resembling a successful status code automatically creates a value.
Accessors have different contracts
The proposed explicit conversion to bool and has_value() report whether the object contains T. Dereference accesses the contained value under a precondition that the value exists. Using it on an error state is undefined behavior under the proposal. The type does not turn unchecked access into automatic error handling.
The value() member has a wider contract. On the error alternative it throws bad_expected_access<E>, which contains the stored error. This gives exception-oriented code a bridge from a returned error object. It does not mean every function returning expected must throw on its ordinary failure path.
Similarly, error() expects the error alternative. A successful object does not contain an additional error payload waiting to be queried. This is why state inspection belongs before selecting a narrow accessor. The representation expresses alternatives, not a pair in which both members are always available.
value_or supplies a fallback value, but it does not express every recovery policy. If one error should produce a default while another must be propagated, the caller needs to inspect the error. The proposal's examples make that distinction explicit rather than presenting a fallback as equivalent to handling every failure in the same way.
The WebKit example gives that distinction a concrete use. Individual IPv4 pieces can produce different parsing errors, and the outer parser accumulates outcomes before deciding which error takes precedence. The first unsuccessful piece is not necessarily the final error returned. Keeping error objects as ordinary values allows the outer algorithm to retain that information while parsing continues. This is a reason to choose an explicit result representation for that algorithm, rather than an assertion that every parser or every C++ error path should adopt the same policy.
I prefer that separation between checking state and choosing policy. A library can carry a domain error without deciding whether its caller should retry or translate it. The returned type preserves the information needed for that decision, while the accessor contract makes unsafe assumptions visible in source.
Never empty does not mean always successful
The design aims to keep an expected object in one of its two meaningful alternatives. Error is a complete state, not an invalid or partially initialized object. This matters when the value or error has nontrivial construction and destruction behavior. The class manages whichever contained object is active.
The proposal also supports expected<void, E>. A successful operation may have no value to return while still needing a typed failure result. The specialization models that success without requiring an arbitrary placeholder data value. R11 defines a separate partial specialization for cv-qualified void value types as part of its wording changes.
Move behavior follows the contained alternative. Moving an object does not automatically switch the source from success to error or the reverse. The underlying value or error can be moved from, but the alternative remains part of the source object's state. A caller should therefore distinguish a moved-from value from absence of a value.
Revision 11 continues an existing design direction
The earlier P0323R10, dated April 15, records LEWG's decision to target the main standard rather than a technical specification. It also restores design rationale that earlier revisions omitted. R11 follows subsequent library reviews by revising conversions and rationalizing constraints and effects.
The history matters because the November paper is not the first presentation of a new error mechanism. It refines a long-reviewed value-or-error design. Related work on monadic interfaces remains separately identified, so the rationale's discussion of composition should not be read as a guarantee that every such convenience operation is included here. The concrete interface provides state inspection, access, and propagation through an explicitly typed result.