std::expected in C++23

std::expected is a type defined in the C++23 standard library as a way of handling errors in C++. It is used to represent the result of an operation that may either produce a value or an error. It provides a way to handle expected results in a type-safe and exception-free manner.

The std::expected template has two template parameters: the first is the type of the value that the operation may produce, and the second is the type of the error that the operation may return. The std::expected object can be in one of two states: a valid state, in which it holds a value, or an invalid state, in which it holds an error.

You can use the std::expected object just like a regular value, with the advantage that you can also check if the operation was successful or not. You can use the value() member function to access the stored value, or the error() member function to access the stored error. If the std::expected object is in the invalid state and you try to access the value, a compile-time error will occur.

Here is an example of using std::expected:

#include <iostream>
#include <expected>
#include <string>

std::expected<std::string, std::string> get_greeting(bool happy)
{
    if (happy) {
        return std::string("Hello, friend!");
    } else {
        return std::make_unexpected(std::string("Oh no, something went wrong."));
    }
}

int main()
{
    auto greeting = get_greeting(true);
    if (greeting) {
        std::cout << *greeting << std::endl;
    } else {
        std::cout << greeting.error() << std::endl;
    }
    return 0;
}

In this example, the get_greeting function returns a std::expected<std::string, std::string> object. If the happy argument is true, the function returns a string with a friendly greeting. If happy is false, the function returns an error message using std::make_unexpected.

In the main function, the code checks the state of the std::expected object. If the std::expected object is in the valid state, it contains the greeting and the code outputs the greeting to the console. If the std::expected object is in the invalid state, it contains the error message and the code outputs the error message to the console.

This example demonstrates how std::expected provides a way to handle expected results in a type-safe and exception-free manner, allowing you to check for success or failure and respond accordingly.

Why exception free

std::expected is exception-free because it doesn’t use exceptions to signal error conditions. Instead, it uses a return value to indicate success or failure, which can be checked using the valid() member function or by casting the std::expected object to a bool.

The advantage of using std::expected over exceptions is that it provides a clear and predictable way to handle error conditions. With exceptions, it can be difficult to know exactly where an exception will be thrown, making it harder to write robust and maintainable code. With std::expected, you can see from the function signature what type of error the function might return, and you can handle the error directly in the code that calls the function. This makes it easier to reason about the behavior of your code and to avoid unintended side effects.

In addition, using std::expected can also be more efficient than using exceptions because it avoids the overhead of constructing and unwinding the stack for each exception. This can make your code faster and more scalable, especially in resource-constrained environments where performance is critical.

This is an update to an earlier article where I explained std::expected before it was introduced to the C++23 standard library.

Leave a Reply