lzon.ca

A result type for C++

Posted June 01, 2026 Updated June 02, 2026 3 min read

I wrote my own version of the very useful ‘result type’ pattern for C++.


The goal of a result type is to provide one of two specific kinds of value as the result of an operation. One representing the typical, or expected outcome. And the other kind representing a secondary or unexpected outcome.

The primary use case is in error handling. If an operation has a more complex error state than a mere boolean flag, then this pattern works very well. A simple example would be a parser. The primary result would be the parsed data structure, while the error would be a detailed list of error messages.

This already exists in Rust through Result<T, E>, which integrates nicely with the overall design of that language.

C++23 also has std::expected, but it is relatively new and has extremely baroque syntax, as is tradition…

The following is my version of the concept, which is valid for C++20. It’s less than 50 lines of code. It’s reasonably efficient. It’s very readable and can be copied easily into an existing codebase.

template <typename Error>
struct failure { Error value; };

template <typename Error>
failure(Error&&) -> failure<std::decay_t<Error>>;

template <typename Value, typename Error>
class result
{
public:
    constexpr result(Value v) : m_data(std::in_place_index<0>, std::move(v)) {}
    constexpr result(failure<Error> e) : m_data(std::in_place_index<1>, std::move(e.value)) {}

    constexpr result& operator=(Value v) { m_data.template emplace<0>(std::move(v)); return *this; }
    constexpr result& operator=(failure<Error> e) { m_data.template emplace<1>(std::move(e.value)); return *this; }

    constexpr explicit operator bool() const noexcept
    { return isValue(); }

    constexpr Value& operator*() { return value(); }
    constexpr Value* operator->() { return &value(); }

    constexpr Value const& operator*() const { return value(); }
    constexpr Value const* operator->() const { return &value(); }

    constexpr bool isError() const noexcept { return m_data.index() == 1; }
    constexpr bool isValue() const noexcept { return m_data.index() == 0; }

    constexpr Value& value() { return std::get<0>(m_data); }
    constexpr Error& error() { return std::get<1>(m_data); }

    constexpr Value const& value() const { return std::get<0>(m_data); }
    constexpr Error const& error() const { return std::get<1>(m_data); }

    constexpr Value valueOr(Value def) const
    { return isValue() ? std::get<0>(m_data) : std::move(def); }

    constexpr Error errorOr(Error def) const
    { return isError() ? std::get<1>(m_data) : std::move(def); }

private:
    std::variant<Value, Error> m_data;
};

Here are a few specific design choices:

  • Error values must be wrapped by a failure struct. This allows for declarations like result<int,int> and makes instantiating the Error value more explicit, and thus more readable.
  • Follows STL conventions for accessing the Value value.
  • Leverages existing std::variant from STL for the sake of simplicity.

Overall it is quite ergonomic to use, as you can see here.

result<int, char const*> parse(string s)
{
    if (s == "a") return 1;
    if (s == "b") return 2;
    if (s == "c") return 3;

    if (s.empty())
        return failure("s is empty");
    return failure("s is invalid");
}

int main(int argc, char** argv)
{
    if (auto r = parse(""))
        cout << "res: " << *r << endl;
    else
        cout << "error: " << r.error() << endl;

    if (auto r = parse("b"))
        cout << "res: " << *r << endl;
    else
        cout << "error: " << r.error() << endl;

    return 0;
}

And that’s it, pretty simple. I mostly did this for fun, but I will be using it in my current project, and otherwise keep it as a new tool that I can use in the future.


Did you find this useful? Do you have any little C++ tricks of your own? If so, Let me know!

Send a message to mail@lzon.ca, or DM me on one of my social accounts on the homepage.
Settings

Theme

Primary
Secondary
Tertiary