std::expected
- C++ course
- Advanced
- Lesson 76/83
- 5 min
Learn error handling with std::expected.
What is std::expected?
std::expected<T, E> is a type introduced with C++23: it holds either a T value or an E error. Instead of throwing an exception, it returns the error as a value.
Example: std::expected<int, std::string> divide(int a, int b). On success return a / b;, on error return std::unexpected(std::string("division by zero"));. The caller checks the state with r.has_value(), gets the value with r.value() and the error with r.error(). This provides error handling without the cost of exceptions; it is especially useful to separate real exceptions from expected failures.
value() and error()
From a std::expected object you get the value with .value() and the error with .error(). You must check .has_value() first.
Example: auto r = divide(10, 2); if (r.has_value()) std::cout << r.value(); else std::cout << r.error();. If you call .value() when there is no value, an exception is thrown. So you must check has_value() first. Errors are produced with std::unexpected: return std::unexpected(std::string("error"));. This is an explicit and type-safe error handling.
Practice Write divide with std::expected
Write std::expected<int, std::string> divide(int a, int b): if b == 0 return std::unexpected(std::string("division by zero"));, otherwise return a / b;. In main call divide(10, 2); if has_value() is true print value(), otherwise print error() with std::cout.
Starter code
#include <iostream>
#include <expected>
#include <string>
// Write the divide function with std::expected
int main() {
// Call divide and print the result
return 0;
}Sample solution
#include <iostream>
#include <expected>
#include <string>
std::expected<int, std::string> divide(int a, int b) {
if (b == 0) return std::unexpected(std::string("division by zero"));
return a / b;
}
int main() {
auto r = divide(10, 2);
if (r.has_value()) std::cout << r.value();
else std::cout << r.error();
return 0;
}Expected output
5
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 When should std::expected be used?
- Always instead of exceptions
- For multithreading
- Only for memory errors
- To return expected error conditions as values Correct answer
Explanation: std::expected returns expected errors as values instead of exceptions.
2 Match each member to its role
| Term | Meaning |
|---|---|
has_value |
Has a value? |
value() |
Get the value |
error() |
Get the error |
std::unexpected |
Produces an error |
3 the .value() call
if (r.has_value()) std::cout << r.____();
if (r.has_value()) std::cout << r.value();
Explanation: r.value() returns the successful result.