C++23 programming language: what else is interesting in the standard

0
20
C++23 programming language: what else is interesting in the standard


C++23 has some important features, but there are also exciting additions to the details.

Advertisement


As a reminder, here are the most important features of C++23.






Rainer Grimm has been working as a software architect, team and training manager for many years. He enjoys writing articles on the programming languages ​​C++, Python and Haskell, but also frequently speaking at specialist conferences. On his blog Modern C++ he discusses his passion C++ in depth.

With this derivation, C++23 extends a small but very effective feature of the original language. Inferring this makes it possible to explicitly dereference the implicitly passed pointer in a member function definition, similar to Python. Thanks to this derivation, some complex techniques in C++, such as CRTP or the overload pattern, become child’s play.

The C++23 library gains several important additional features. You can use the standard library directly import std; Import or C++20 format strings std::print And std::println Applying. We also get flat associative containers for performance reasons std::flat_map. std::flap_map is a drop-in replacement for std::map. std::optional This has been extended to include a monadic interface for compatibility reasons. New data types std::expected It already has a composable interface and can store expected or unexpected values ​​for error handling. Thanks to std::mdspan We get a multidimensional expansion. std::generator Finally, the first concrete coroutine is for generating a stream of numbers. std::generator is part of the range library, which has also been improved in C++23.

More details can be found in my previous articles:

original language

  1. C++23: Deducing makes this an explicit pointer
  2. C++23: syntactic sugar with minification
  3. C++23: Little pearls in the core language
  4. C++23: More little gems in the core language

Library

  1. C++23: A modular standard library and two new functions
  2. Categories: Improvements with C++23
  3. C++23: A new way of error handling with std::expected
  4. C++23: Four new associative containers
  5. C++23: A multidimensional view

But that’s not all that C++23 has to offer.

As of now, C++ supports the following data types:

  • no suffix: double
  • F or f suffix: float
  • l or l suffix: long double

C++23 introduces five new literal suffixes. The table on cppreference shows their data types and their properties:



The new data types are in the header defined. You can use predefined macros to check whether your own implementation supports the new data types.

Analyzing the current stack is often very useful for troubleshooting. The new StackTrace library offers exactly that.

The library has two classes:

  • stacktrace_entry: Representation of evaluation in a stack trace
  • basic_stacktrace: Snapshot of the entire stack trace or a specific part

In simple terms: with class stacktrace_entry You can find information about the evaluation in the stack trace. Each stacktrace_entryThe object is either empty or represents an evaluation in the stack trace.

Class basic_stacktrace A snapshot of the entire stack trace or a specific part of it.

Still confusing?

In the following simple example main Implement the function func1 But, func1 Call func2 but and func2 Call func3 But.

// stacktrace1.cpp

#include 
#include 

 
void func3() {
    std::cout << std::stacktrace::current()  << '\n';
}
 
void func2() {
    func3();
}
 
void func1() {
    func2(); 
}
 
int main() {
    func1();
}

func3 calls a static function current But std::stacktrace But. std::stacktrace is a nickname for std::basic_stacktrace With the standard allocator.

Provides information about the stack trace when the program is executed.

Compiling the program using the compiler explorer was quite a challenge. It took me a while to locate the appropriate GCC version and libraries.

Here is the command line for g++13.1: g++ -std=c++23 -lstdc++_libbacktrace,

thanks to std::stacktrace_entry The stack trace can be interrogated.

// stacktrace2.cpp

#include 
#include 

 
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();
}

At the ceremony func3 I loop through the stack trace entries and display their details, file and line clearly.

I will write only a few words about the remaining features of C++23. The examples come from cppreference.com.

I’d like to start with two characteristics that can affect a program’s performance.

can do std::unreachable Use to mark code that cannot be reached. Calling std::unreachable results in 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();
}

with C++11 std::function. std::function is a polymorphic function wrapper and can accept arbitrary callable calls and give them a name. Callables are any entities that behave like functions, such as functions, function objects, or lambdas.

more about std::function You can find out here: Functional in TR1 and C++11,

as a protest std::function be able to std::move_only_function Receive only one constructible callable. The callable object can contain std::move_only_function To avoid additional storage requirements.

// from https://en.cppreference.com/w/cpp/utility/functional/move_only_function


auto lambda = (task = std::move(packaged_task))() mutable { task(); };
 
//  std::function function = std::move(lambda); // Error
std::move_only_function function = std::move(lambda); // OK
 

std::byteswap Swaps the bytes in a value n. n Sure Integrals Happen.

The following program applies std::byteswap To.

// from https://en.cppreference.com/w/cpp/numeric/byteswap

#include 
#include 
#include 
#include 
#include 
 
template<: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(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.



In my next article I will discuss C++26.


(RME)

LEAVE A REPLY

Please enter your comment!
Please enter your name here