Newsletter 2

New feature in C++ 23

Hello everyone!
This newsletter will be talking about a recently added feature to C++ 23.

You might ask, why care about C++ 23 when I can do almost everything I need with the previous versions?

C++ keeps evolving, with each standard balancing safety, performance, and expressiveness.

C++23 focuses more on quality-of-life features than revolutionary changes.

Let’s look at one such feature.

std::expected

If you’ve ever struggled with mixing exceptions, error codes, or std::optional, std::expected might just be the tool you’ve been waiting for.

It is a type designed to simplify error handling while keeping your code explicit and type-safe.

Think of it as a container that either holds a valid result or an error. Unlike exceptions, it doesn’t rely on hidden control flow, everything is explicit.

Unlike std::optional, it can carry meaningful error information.

Ex:

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

std::expected<int, std::string> divide(int a, int b) {
    if (b == 0)
        return std::unexpected("Division by zero");
    return a / b;
}

int main() {
    auto result = divide(10, 0);

    if (!result)
        std::cout << "Error: " << result.error() << "\n";
    else
        std::cout << "Result: " << *result << "\n";

    result = divide(4, 2);

    if (!result)
        std::cout << "Error: " << result.error() << "\n";
    else
        std::cout << "Result: " << *result << "\n";

}

Output:

Error: Division by zero
Result: 2

Why it’s useful:

  • Explicit: You can’t ignore errors accidentally.
  • Composable: Works nicely with functions returning other std::expected values.
  • Safe: No exceptions to catch, no hidden control flow.

A few basic operations on this datatype:

Let’s start with this:

std::expected<int, std::string> result = divide(x, y);

Access:

if(result) {
    /* if this block is entered,
    result has the value and not
    the error */

    /* the following can be done
    to access the value field */
    int a1 = *result;
    int a2 = result.value();
}

if(!result) {
    /* if this block is entered,
    result has the error and not
    the value */

    /* the following can be done
    to access the error field */
    std::string err = result.error();
}

Accessing the value when there’s an error (or the error when there’s a value) is unsafe; use if(result) or .value_or() to avoid exceptions or undefined behavior.

std::expected<T, E>::value_or(T default_value)

  • It is a very handy member function that lets you provide a fallback value if the std::expected contains an error.
  • It’s a safer and more concise way to handle errors than manually checking with if(result) or using exceptions.

Consider:

int a1 = result.value_or(-1);
std::cout << a1 << std::endl;
  • Here if result has a value then a1 also has that value.
  • Otherwise, if result contains an error, then the value of a1 will be -1.

Comparison:

std::expected<int, std::string> a = 10;
std::expected<int, std::string> b = 10;
if (a == b) { /* true */ }

std::expected<int, std::string> c = std::unexpected("fail");
if (a != c) { /* true */ }

Composable operations:

std::expected supports functional-style operations like and_then and transform to chain computations safely:

auto result_pass = divide(20, 2)
                    .and_then([](int x){ return divide(x, 2); })
                    .transform([](int x){ return x * 3; });

std::cout << "Case 1: " << result_pass.value_or(-1) << "\n";


auto result_fail = divide(20, 0)  // division by zero
                    .and_then([](int x){ return divide(x, 2); })
                    .transform([](int x){ return x * 3; });

std::cout << "Case 2: " << result_fail.value_or(-1) << "\n"; 
  • and_then runs the lambda only if the previous result is valid.
  • transform applies a function to the value without touching the error.
  • value_or(-1) provides a fallback if any error occurred in the chain.

Output:

Case 1: 15
Case 2: -1

There are many more things that can be done with std::expected.

Author – ScepticallySam


Interesting Resources

Interesting Read

You can check the link for more examples.

Read More
Icon 1

Interesting Video

A YouTube video about the new feature.

Read More
Icon 2