C++23: This and That
I have already written 10 posts about C++23. Today, I want to discuss the features I forgot in the first round.
As a short reminder, here are the main C++23 features.
Main C++23 Features
C++23 offers with deducing this a small but very impactful feature of the core language. Deducing this allows you, similar to Python, to make the implicitly passed this pointer in a member function definition explicit. Thanks to deducing this, a few complex techniques in C++, such as CRTP or the Overload Pattern, will become a piece of cake.
The C++23 library will get many impactful additions. You can directly import the standard library with import std;, or apply the C++20 format string in std::print and std::println. Additionally, we will get flat associative containers such as std::flat_map for performance reasons. std::flap_map is a drop-in replacement for std::map. std::optional interface is extended with a monadic interface for composability. The new data type std::expected already has a composable interface and can store an expected or an unexpected value for error handling. Thanks to std::mdspan, we will get a multidimensional span. Finally, std::generator is the first concrete coroutine for creating a stream of numbers. std::generator is part of the ranges library, which will also be improved in C++23.
If you need more details, read my previous posts.
Core Language
Library
This is not all.
Fixed Width Floating Point Types
So far, C++ supports the following floating point types:
With C++23, we will get five new literal suffixes.
?
?
The table from cppreference shows their types and their properties.
The new data types are defined in the header <stdfloat>. You can check with the corresponding predefined macro, if your implementation supports the new data types. Then the macro is 1.
Stacktrace
Analyzing the current call stack is often very useful for debugging. The new stack trace library supports precisely this.
The library consists of two classes:
Let me put this in simpler words. The stacktrace_entry class lets you get information about an evaluation in a stack trace. Each stacktrace_entry object is either empty, or represents an evaluation in a stack trace.
The basic_stacktrace class is a snapshot of the whole stack trace or its given part.
Still not clear?
In the following simple example, the main function invokes the func1 function, func1 invokes func2, and func2 invokes func3.
// stacktrace1.cpp
#include <iostream>
#include <stacktrace>
void func3() {
std::cout << std::stacktrace::current() << '\n';
}
void func2() {
func3();
}
void func1() {
func2();
}
int main() {
func1();
}
func3 calls the static function current on std::stacktrace. std::stacktrace is an alias for std::basic_stacktrace with the default allocator.
领英推荐
Executing the program gives you information about the stack trace.
Compiling the program on the Compiler Explorer was pretty challenging. It took me a while to find the appropriate GCC version and the libraries.
Here is the command line for g++ 13.1: g++ -std=c++23 -lstdc++_libbacktrace.
Thanks to the std::stacktrace_entry, you can query the stack trace.
// stacktrace2.cpp
#include <iostream>
#include <stacktrace>
void func3() {
auto stacktrace = std::stacktrace::current();
for (const auto& entry: stacktrace) {
std::cout << "Description: " << entry.description() << '\n';
std::cout << "file: " << entry.source_file() << " and line: " << entry.source_line() <<'\n';
std::cout << '\n';
}
}
void func2() {
func3();
}
void func1() {
func2();
}
int main() {
func1();
}
In the function func3, I iterate through the stack trace entries and expressly display its description, file, and line.
I will only write a few words about the remaining C++23 features. The examples are from cppreference.com.
Let me start with two features which may affect the performance of your program.
std::unreachable
You can use std::unreachable it to mark code that isn’t reachable. When you call std::unreachable, you’ll get undefined behavior.
// from https://en.cppreference.com/w/cpp/utility/unreachable
switch (xy)
{
case 128: [[fallthrough]];
case 256: [[fallthrough]];
case 512: /* ... */
tex.clear();
tex.resize(xy * xy, Color{0, 0, 0, 0});
break;
default:
std::unreachable();
}
std::move_only_function
With C++11 we got std::function. std::function is a polymorphic function wrapper. Therefore, it can take arbitrary callables and give them a name.? Callables are all entities that behave like functions, such as functions, function objects, or lambdas.
Read more about std::function here: Functional in TR1 and C++11.
On the contrary to std::function, can std::move_only_function only get a constructible callable. The callable object may be stored in the std::move_only_function to avoid memory allocation.
// from https://en.cppreference.com/w/cpp/utility/functional/move_only_function
auto lambda = [task = std::move(packaged_task)]() mutable { task(); };
// std::function<void()> function = std::move(lambda); // Error
std::move_only_function<void()> function = std::move(lambda); // OK
std::byteswap
std::byteswap swaps the bytes in the value n. n must be integral.
The following program applies std::byteswap.
// from https://en.cppreference.com/w/cpp/numeric/byteswap
#include <bit>
#include <concepts>
#include <cstdint>
#include <iomanip>
#include <iostream>
template<std::integral T>
void dump(T v, char term = '\n')
{
std::cout << std::hex << std::uppercase << std::setfill('0')
<< std::setw(sizeof(T) * 2) << v << " : ";
for (std::size_t i{}; i != sizeof(T); ++i, v >>= 8)
std::cout << std::setw(2) << static_cast<unsigned>(T(0xFF) & v) << ' ';
std::cout << std::dec << term;
}
int main()
{
static_assert(std::byteswap('a') == 'a');
std::cout << "byteswap for U16:\n";
constexpr auto x = std::uint16_t(0xCAFE);
dump(x);
dump(std::byteswap(x));
std::cout << "\nbyteswap for U32:\n";
constexpr auto y = std::uint32_t(0xDEADBEEFu);
dump(y);
dump(std::byteswap(y));
std::cout << "\nbyteswap for U64:\n";
constexpr auto z = std::uint64_t{0x0123456789ABCDEFull};
dump(z);
dump(std::byteswap(z));
}
Finally, here is the output of the program.
What’s Next?
With my next post, I jump into C++26
C++ Developer
3 个月Your posts about modern chrono library really helped me out a few days ago. Thank you for that!