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.
Similar Reads
C++ 11 - <cstdint> Header
<cstdint> header in C++ ensures the portability of integer types with specialized width and signedness across various systems. The absence of standardization for integer types caused issues in coding and constructing portable programs before the advent of. In this article, we will explore the
3 min read
C++ 11 - <cfenv> Header
C++ 11 comes with new features and improvements and one of the main addition is the <cfenv> header that helps the programmers or developers with great control over the floating-point environment. It governs critical features of floating-point arithmetic like rounding modes and exceptions. <
4 min read
C++ 11 - <cinttypes> Header
The header offers type aliases and functions for manipulating integer types with particular sizes and signedness, as a part of the C++11 standard. Its aim is to present a standard group of integer types across diverse platforms and architectures. <cinttypes> header The <cinttypes> header
2 min read
C++23 <print> Header
C++ has long been a powerful language, known for its versatility and performance. With each new standard release, the language evolves, introducing features that enhance developer productivity and code readability. One of these additions of the C++ 23 standard is the introduction of <print> he
3 min read
C++17 - <charconv> Header
The C++ header provides many functions for converting the character sequences to numerical values and vice-versa. It is considered better than the header file functions for the same purpose. The functions provided by the header file are generally faster than the functions provided by the header file
5 min read
C++ 20 - <numbers> Header
C++20 has a recently developed header file labeled that incorporates mathematical functions and constants. Its purpose is to provide standard library support for mathematical operations, simplifying the process for C++ programmers to incorporate mathematical functions and constants into their progra
3 min read
C++ 23 <stacktrace> - Header
Imagine you're on an adventure, exploring a vast and dense forest. Along the way, you encounter challenges that might leave you feeling lost or confused. In such situations, a map or compass would be invaluable tools to guide you back on track. Similarly, in the world of programming, stack traces se
5 min read
C++ <cstdio>
The <cstdio> header file is a part of the C++ standard library collection that provides the input and output methods of <stdio.h> library of C language. We can use the traditional C-style input and output method in C++ using the <cstdio> library. It also contains all the functions
7 min read
C++23 Library - <spanstream> Header
The <spanstream> header is a new addition to C++ 23 Standard Libraries Collection. It provides fixed character buffer streams for input and output. It is a collection of classes and function templates that let you manipulate letter stretch as if they were streams, much like <stringstream
3 min read
clocale header file in C++
clocale: This header file contains declaration of a set of functions and a type for internationalization support tasks. It supports date format or country specific currency symbols. For example, date/time formatting, monetary formatting and many more. Methods in clocale header: localeconv(): This fu
2 min read