C++23 – <expected> Header
Last Updated :
22 Sep, 2023
C++23, the next major version of the C++ programming language, brings several exciting features and enhancements. One of the significant additions in C++23 is the <expected> header, which aims to improve error handling and make code more robust and readable. In this article, we will explore the feature of <expected> header, its purpose, and how it simplifies error handling in C++.
Problem with Error Handling
Error handling in C++ has historically been a complex and error-prone task. C++ has exceptions and error codes, but choosing the right approach and implementing error handling consistently across a codebase can be challenging. Additionally, exceptions can introduce performance overhead in certain scenarios.
<expected> Header in C++
The <expected> header in C++23 introduces a new way to handle errors and expected values. It is inspired by similar constructs in other programming languages, such as Rust’s Result and Swift’s Result types. The primary goal of <expected> is to provide a more explicit and structured way to handle expected values and errors without relying solely on exceptions or error codes.
The <expected> header introduces two main class templates:
- std::expected
- std::unexpected
Let’s dive into each of them.
1. std::expected Class Template
The std::expected is a class template in C++ that serves as a mechanism for managing functions that may return either a valid result or an error. It is a wrapper that is particularly useful in scenarios where exceptions might not be the preferred error-handling approach.
Syntax
The std::expected is used as the value return by the function as shown below:
std::expected<T, E> function_name {
// statements
}
where,
- T: This parameter represents the type of the expected (valid) value that the function may return when it succeeds.
- E: This parameter represents the type of error condition that the function may return when it fails.
When a function returns an instance of std::expected, the caller can easily check whether the result is valid (contains a value of type T) or represents an error (contains an error of type E). This approach provides a clear and structured way to handle errors in a functional, non-exception-based manner.
std::expected Member Functions
Following are some commonly used Member functions of the std::expected class:
S.No.
|
Function
|
Description
|
1
|
value() |
It allows you to retrieve the stored value of type T. |
2
|
error() |
This one facilitates access to the stored error of type E. |
3
|
has_value(): |
This member function is used to inquire whether the std::expected contains a value or not. It returns true if the std::expected holds a value and false if it holds an error. |
4
|
error_code() |
When applicable, this member function is employed to convert the stored error into an error code. |
2. std::unexpected Class Template
The std::unexpected is not a standalone class but rather a concept used with std::expected. It helps to define how unexpected errors are handled within a specific context.
When an unexpected error occurs within a function that returns a std::expected, the function can use std::unexpected to specify what action should be taken. This allows developers to define a custom response to unexpected errors.
Syntax
std::expected<T, E> function_name {
// statements
return std::unexpected< E >(some_value);
}
where,
- E: The error type specified in std::expected template.
How to use std::expected?
To use the std::expected class template, follow the given steps:
- Create an instance of std::expected with the expected value type (T) and the error type (E).
- In case of an error, return an instance of std::expected with the error type (E).
- When an operation succeeds, return an instance of std::expected with the expected value (T).
- Utilize methods like has_value() and value() to access the value or error() to obtain the error, as needed.
Examples
Below given is the example code that uses expected in C++:
Example 1: Handling a Successful Division
C++
#include <expected>
#include <iostream>
using namespace std;
expected< int , string> divide( int a, int b)
{
if (b == 0) {
return unexpected<string>( "Division by zero" );
}
return a / b;
}
int main()
{
auto result = divide(10, 2);
if (result.has_value()) {
cout << "Result: " << result.value() << endl;
}
else {
cerr << "Error: " << result.error() << endl;
}
return 0;
}
|
Output
Result: 5
In this example, the divide function returns a std::expected<int, std::string>, representing the result of division or an error message for division by zero.
Example 2: Handling Division by Zero
C++
#include <expected>
#include <iostream>
using namespace std;
expected< int , string> divide( int a, int b)
{
if (b == 0) {
return unexpected<string>( "Division by zero" );
}
return a / b;
}
int main()
{
auto result = divide(10, 0);
if (result.has_value()) {
cout << "Result: " << result.value() << endl;
}
else {
cerr << "Error: " << result.error() << endl;
}
return 0;
}
|
Output
Error: Division by zero
Example 3: Using a Different Error Type
C++
#include <expected>
#include <iostream>
using namespace std;
expected< int , float > divideWithFloatError( int a, int b)
{
if (b == 0) {
return unexpected< float >(0.0f);
}
return a / b;
}
int main()
{
auto result3 = divideWithFloatError(6, 0);
if (result3.has_value()) {
cout << "Result 3: " << result3.value() << endl;
}
else {
cerr << "Error 3: " << result3.error() << endl;
}
return 0;
}
|
Output
Error 3: 0
Advantages of using std::expected
The <expected> header brings forth a multitude of benefits:
- std::expected makes error handling simple and concise within code. It distinctly separates the expected and error scenarios.
- The C++ type system ensures that you cannot inadvertently mix up expected values and errors.
- std::Expected is designed with minimal performance overhead, ensuring efficient error handling.
Conclusion
The <expected> header in C++23 represents a significant leap forward in error handling for C++ developers. With improved code clarity, type safety, and performance characteristics, it offers an efficient solution for handling expected values and errors gracefully.
Share your thoughts in the comments
Please Login to comment...