std::expected<>

Written by on May 13, 2023 in C++, Programming with 0 Comments

I had written about std::optional<> in an earlier article. C++23 introduces std::expected<> as an interesting extension to std::optional<>. Whereas std::optional<> contains a value or none at all, std::expected<> contains a value or an error code associated with it. This gives better control to the caller in terms of handling the outcome of the function call.
Let us look at an example to get started:

An Example

An Example

In the above example, function “foo()” takes an integer and returns either an integer or an error code. If the supplied argument is between 10 and 100 (both included), then it returns a computed value, else it returns an error code of type “ErrCode”.

Let us see how this function is called inside “main()”. The first call (line 25) passes “-100”, which is outside the acceptable range. In this case, obviously, we expect the function to return an error code. The “result” variable will be “true” if the function returned a computed value, false if an error code was returned. This is checked in lines 26 – 29 and corresponding value printed. Notice the use of “value()” and “error()” member function calls to access the computed value and the error code respectively. This is convenient.

Next, Line 32 passes a valid argument to the “foo()” function. In this case, the “result” variable will be “true” and hence line 34 will be executed.

Program Output

Program Output

As in the case of std::optional<>, there is a “value_or()” member function that returns either the normal value, or in the case of an error return, the user-supplied value. This is shown in line 39.

Use of "value_or"

Use of “value_or”

In the case, because the supplied argument is outside the permitted range, an error code will be returned. Hence the “value_or()” function will return “99999” instead of the error code. This is convenient when we cascade function calls.

Output from "value_or()"

Output from “value_or()”

We have seen how the member function “value()” allows us to retrieve the normal return value from the function. What happens if we call this function when the function returns an error code? This is a fatal error and hence the program will be aborted. See line 44 below:

Incorrect Use of "value()"

Incorrect Use of “value()”

Here is what happens when we run the program:

Abnormal Program Termination

Abnormal Program Termination

Finally, can std::expected<> be used with “void” returning functions? Yes, that is possible. See this code snippet:

Using with "void"-returning Function

Using with “void”-returning Function

Of course, in this case, there is no “normal” return value, but we can access the error code, if any, as usual.

Program Output

Program Output

It is a matter of debate/style whether such functions should return the error code via the normal return type or should use std::expected<>. I personally prefer the former.

I should stress at this point that std::expected<> does not replace the correct use of exceptions in the code. When to “return” an error code or “throw” an exception is an important design decision and must be taken seriously.

I tried the above example in Visual Studio Professional (64 bit) Ver 17.5.5 on Windows 10. You can download the source from here.

Have a nice weekend!

Tags: ,

Subscribe

If you enjoyed this article, subscribe now to receive more just like it.

Subscribe via RSS Feed

Leave a Reply

Your email address will not be published. Required fields are marked *

Top