std expected
std::expected<T, E> came originally from an experimental monadic and generic programming library outside of Boost written by Boost and WG21 developers around 2013. Before Outcome v1, I deployed the then Expected into a large codebase and I was dismayed with the results, especially on build times. You can read here how those experiences led me to develop Outcome v1.
std::expected<T, E> is a constrained variant type with a strong preference for the successful type T which it models like a std::optional<T>. If, however, there is no T value then it supplies an ‘unexpected’ E value instead. std::expected<T, E> was standardised in the C++ 23 standard.
Outcome’s Result type can be configured to act just like Expected if you want that, however ultimately Outcome’s Result doesn’t solve the same problem as Expected, plus Outcome models std::variant<T, E> rather than std::optional<T> which we think much superior for many use cases, which to summarise:
- If you are parsing input which may rarely contain unexpected values, Expected is the right choice here. 
- If you want an alternative to C++ exception handling i.e. a generalised whole-program error handling framework, Expected is an inferior choice to alternatives. 
Outcome recognises Expected-like types and will construct from them, which aids interoperability.
Pros:
- Predictable runtime overhead on the happy path. 
- Predictable runtime overhead on the sad path. 
- Very little codegen bloat added to binaries (though there is a fixed absolute overhead for support libraries). 
- Variant storage means storage overhead is minimal, except when either - Tor- Ehas a throwing move constructor which typically causes storage blowup.
- Works well in all configurations of C++, including C++ exceptions and RTTI globally disabled. 
- Works well on all niche architectures, such as HPC, GPUs, DSPs and microcontrollers. 
- Ships with every standard library since C++ 23. 
Cons:
- Success-orientated syntax makes doing anything with the - Etype is awkward and clunky.
- Results in branchy code, which is slow – though predictably so – for embedded controller CPUs. 
- Failure to examine an Expected generates a compiler diagnostic, but failure to handle both failure and success does not. This can mean failures or successes get accidentally dropped. 
- Lack of a - tryoperator makes use tedious and verbose.
- Variant storage does have an outsize impact on build times in the same way widespread use of - std::varianthas. This is because implementing exception guarantees during copies and moves of non-trivially-copyable types in union storage involves a lot of work for the compiler on every use of copy and move.



