Articles & Books

C++26: string and string_view improvements -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGLet’s continue our exploration of C++26 improvements. Today we focus on string_view. Some types got new constructors accepting string_views, and concatenation of strings and string_views just got easier.

C++26: string and string_view improvements

by Sandor Dargo

From the article:

But let’s start with a brief reminder of what a string_view is.

Reminder: the role of string_view

std::string_view was introduced in C++17 and its purpose is to provide read-only access to a string-like object. It can often replace const string& parameters and offers a significant performance gain. It’s generally advisable to use it whenever you’d pass an immutable string-like input that you cannot move from source to target.

We covered the topic earlier in more depth here.

P2495R3: Interfacing stringstreams with string_view

A stringstream is a good old tool for dealing with operations on string-based streams. While C++23 introduced spanstreams, due to fundamental semantic differences, stringstreams are not dead and it’s important to maintain them.

Being a good old tool also means they predate string_view. Given the available set of constructors, if you want to initialize a stringstream from a string_view, you first have to manually convert it into a string.

P2495R3 fixes this by adding new constructors accepting string_views.

It’s worth noting that this is a purely additive library change — it doesn’t break existing code.

At the moment of publication, this change is already available on Clang 19.

New features in GCC 16: Improved error messages and SARIF output -- David Malcolm

redhatgraphic.pngGCC 16 is about to be released, so I'm sharing some of the new features I worked on this year. Some changes are visible to users, while others improve the system more subtly.

New features in GCC 16: Improved error messages and SARIF output

by David Malcolm

From the article:

A well-known challenge for C++ developers is the readability of template-related error messages. C++ compilers tend to either provide too little information or spew screenfuls of text at you. Either way, the errors can be difficult to decipher.

GCC error messages have a hierarchical structure to them. In GCC 15, I added an experimental option that shows this structure as a collection of nested bullet points.

In GCC 16, this behavior is now the default. You can return to the previous behavior using -fno-diagnostics-show-nesting or -fdiagnostics-plain-output. I fixed several bugs and made use of the hierarchical structure in more places. For example, it is easy to get declarations and definitions out of sync when manually adding const to a parameter:

class foo
{
  public:
    void test(int i, int j, void *ptr, int k);
};
    
// Wrong "const"-ness of param 3.
void foo::test(int i, int j, const void *ptr, int k)
{
}

C++26: Structured Bindings can introduce a Pack -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGIn previous posts, we talked about how C++26 improves structured bindings by allowing them to be used in conditionals’ init statements. We also briefly touched on other improvements coming in C++26, such as individual binding annotations and constexpr bindings. There is, however, one important enhancement to structured bindings that we haven’t covered yet on this blog: Structured Bindings can introduce a Pack

C++26: Structured Bindings can introduce a Pack

by Sandor Dargo

From the article:

Before diving into the feature itself, let’s briefly clarify what a pack is. A reasonably accurate (and not overly simplistic) definition is the following:

A parameter pack is a language construct that represents an arbitrary number of types or values, allowing code to accept and operate on an arbitrary number of arguments in a type-safe way.

I deliberately avoided using the word template in this definition. Historically, packs only existed in templated contexts, but that limitation is slowly being relaxed. Earlier versions of the proposal behind this feature even aimed to support structured binding packs in non-templated contexts. That part was eventually dropped due to implementation complexity and related objections — but the direction is still telling.

Annotations for C++26 Hashing -- Krystian Piękoś

Static reflection already makes generic hashing in C++26 far more expressive, but annotations push it into genuinely ergonomic territory. By letting types explicitly opt-in to hashing and allowing individual members or base classes to be cleanly excluded, we get a solution that is both powerful and readable.

Annotations for C++26 Hashing

by Krystian Piękoś

From the article:

In my recent post, I demonstrated how to use static reflection from C++26 to implement generic hash computation for custom types. Let's review the final implementation. The core of the solution is the calculate_hash() function, which iterates over sub-objects (including both base classes sub-objects and class/struct non-static data members) to compute a combined hash.

template <typename T>
concept Hashable = requires {
  { std::hash<T>{}(std::declval<T>()) } -> std::convertible_to<size_t>;
};

template <typename T>
  requires std::is_class_v<T>
size_t calculate_hash(const T& obj, size_t seed = 0)
{
  constexpr auto ctx = std::meta::access_context::unchecked();

 
  static constexpr auto r_subobjects = std::define_static_array(std::meta::subobjects_of(^^T, ctx));

  template for (constexpr auto r_sub : r_subobjects)
  {
    using Subobject_t = typename[:std::meta::type_of(r_sub):];
    static_assert(Hashable<Subobject_t>, "Subobject must be hashable");
    Utility::hash_combine(seed, obj.[:r_sub:])
  }

  return seed;
}

How ref qualifiers led to deducing this

A follow up on last weeks post on ref qualifiers:

How ref qualifiers led to deducing this

by Jens Weller

From the article:

Last week I shared an overview on ref qualifiers with you, this is a follow up on this post. Featuring deducing this, a C++23 feature that should be available in your compiler if its been released in 2025 or later.

Lets start with two more things you may want to know about ref qualifiers. First, const is also supported for the rvalue version: m::f()const && exists, though this is mostly not very useful. Thats why you rarely see it covered, as const rvalues are unusual to unvalid. But thats where m::f()const&&=delete comes in, it allows you to turn these object states in to compilation errors.

As ref qualifiers are also often used...

 

C++26: Structured Bindings in Conditions -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGStructured bindings in conditions may look like a small syntax sugar, but they let us write much more expressive conditional logic. By allowing decomposition and condition checking to live side by side, C++26 reduces boilerplate, improves locality, and better supports modern result types that bundle status and data together. This is a pragmatic, well-integrated evolution of a feature that has already proven its value since C++17.

C++26: Structured Bindings in Conditions

by Sandor Dargo

From the article:

Structured bindings were introduced in C++17 as an alternative way of declaring variables. They allow you to decompose an object into a set of named variables, where the collection of those bindings conceptually represents the original object as a whole.

// https://godbolt.org/z/97GaMajMP

#include <cassert> #include <string> 
struct MyStruct {
    int num;
    std::string text;

    bool operator==(const MyStruct&) const noexcept = default;
};

MyStruct foo() {
    return {42, "let's go"};
}

int main() {
    const auto& [n, t] = foo();
    MyStruct ms{n, t};
    assert(ms == foo());
    return 0;
}

Let the Compiler Check Your Units -- Wu Yongwei

logo.pngMixing your units can be disastrous. Wu Yongwei takes a quick look at C++ unit libraries that can help keep everything in order.

Let the Compiler Check Your Units

by Wu Yongwei

From the article:

I recently came across a C++ standard proposal P3045 [P3045R7], which aims to add physical units to C++. Curious, I looked into the existing unit libraries and went down quite a rabbit hole.

Type safety and user-defined literals

Before exploring these libraries, I was already somewhat familiar with the idea of ‘type safety’. I was also aware that user-defined literals (UDLs) [CppReference-1] allow creating literals of specific types with ease. Typical uses in the standard library include string/string_view literals and the chrono library [CppReference-2], which make code both convenient and safe.

Figure 1 shows some simple examples.

auto msg = "Hello "s + user_name;
auto t1 = chrono::steady_clock::now();
this_thread::sleep_for(500ms);
auto t2 = chrono::steady_clock::now();
auto duration = t2 - t1;
auto what = t1 + t2;      // Can't compile
cout << duration / 1.0ms; // To double, in ms

Exploring ref qualifiers in C++

Recently I've been wondering about ref qualifiers in C++.

Exploring ref qualifiers in C++

by Jens Weller

From the article:

Ref qualifiers are today an old C++11 feature, and recently I wanted to know more about them. Especially their potential use cases.

Thats a particular point with this feature, I've seen examples - but often without a compelling use case. This feature is a great way to achieve very specific things in C++...

 

What reinterpret_cast doesn't do -- Andreas Fertig

Depositphotos_347968346_S.jpgIn today's post, I will explain one of C++'s biggest pitfalls: reinterpret_cast. Another title for this post could be: This is not the cast you're looking for!

What reinterpret_cast doesn't do

Andreas Fertig

From the article:

My motivation for this blog post comes from multiple training classes I thought over the past several months and a couple of talks I gave. Since C++23, you have a new facility in the Standard Library: std::start_lifetime_as. When teaching class with a focus on embedded environments or presenting talks with such a focus, I started to add std::start_lifetime_as to the material. With an interesting outcome.

The feedback I get is roughly:

  • why do I need std::start_lifetime_as, I already have reinterpret_cast?
  • why can I use reinterpret_cast?

If you never heard of start_lifetime_as please consider reading my post, The correct way to do type punning in C++ - The second act.

What Happens When a Destructor Throws -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGEven experienced C++ developers sometimes stumble on a deceptively simple question: what actually happens when a destructor throws an exception? This post breaks down the mechanics behind stack unwinding, noexcept, and why throwing from destructors is almost always a bad idea

What Happens When a Destructor Throws

by Sandor Dargo

From the article:

Recently I wrote about the importance of finding joy in our jobs on The Dev Ladder. Mastery and deep understanding are key elements in finding that joy, especially now that generating code is cheap and increasingly done better by AI than by us.

Then a memory surfaced. I frequently ask during interviews — as part of a code review exercise — what happens when a destructor throws. Way too many candidates, even those interviewing for senior positions, cannot answer the question. Most say it’s bad practice, but cannot explain why. Some say the program might terminate. Getting an elaborate answer is rare.

I’m not saying it’s a dealbreaker, but it definitely doesn’t help.

Let’s see what actually happens.

The role of a destructor

A destructor is the key to implementing the RAII idiom. RAII matters because after you acquire a resource, things might go south. A function might need to return early, or it might throw. Making sure resources are released is cumbersome, and the cleanest way to achieve it is to wrap both acquisition and release in an object that handles this automatically.

But what if the release itself is not successful?

Destructors have no return value, so error reporting is limited. Typical options include logging, storing error state, or (discouraged) throwing.

Why did I mark throwing an exception discouraged?