Articles & Books

C++26: std::format improvement (Part 1) -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGC++26 brings a series of improvements to std::format, continuing the work started in C++20 and refined in C++23. These changes improve formatting consistency, runtime safety, and user ergonomics. There are so many of these updates, that I decided to divide them into two articles.

C++26: std::format improvement (Part 1)

by Sandor Dargo

From the article:

Arithmetic overloads of std::to_string and std::to_wstring use std::format

P2587R3 by Victor Zverovich proposes replacing sprintf with std::format in the arithmetic overloads of std::to_string and std::to_wstring.

The motivation?

std::to_string has long been known to produce not-so-great and misleading results (differing from iostreams), especially with floating-point values. std::to_string uses the global C locale. In practice, it’s unlocalized. Also, it often places the decimal points to suboptimal places:

std::cout << std::to_string(-1e-7); // prints: -0.000000 
std::cout << std::to_string(0.42); // prints: 0.420000
These outputs are imprecise and often unnecessary. By leveraging std::format (and ultimately std::to_chars), we now get clearer, shorter representations. The representations of floating-point overloads become also unlocalized and use the shortest decimal representations.

As a result, the above outputs would change as follow:

    std::cout << std::to_string(-1e-7);  // prints: -1e-7
    std::cout << std::to_string(0.42); // prints: 0.42

Once More About dynamic_cast, a Real Use Case -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGWhile dynamic_cast is often discouraged for its impact on readability and reliance on RTTI, there are rare situations where it can be the most practical and safe solution. In this post, we explore one such real-world case: using dynamic_cast for runtime versioning of plugin interfaces in a way that balances compatibility, safety, and extensibility.

Once More About dynamic_cast, a Real Use Case

by Sandor Dargo

From the article:

I wrote a couple of times about dynamic_cast and I discouraged you from using it. In general, it makes code worse in terms of readability. When you get rid of dynamic_cast, either via self-discipline or by turning RTTI off, you’ll have to rely on dynamic dispatching and better abstractions.

But there might be cases, when it’s not possible or at least it’s not meaningful to remove dynamic_cast, here is one, sent by one of you.

Versioning with the help of dynamic_cast

They have an SDK that anyone can implement. As there are new features added every now and then, the API keeps changing. Not surprisingly, the owners of the SDK want to prevent their users’ code from breaking. They achieve this by having different “versioned” interfaces for the same service where a new version inherits from the previous one.

Let’s see a simplified example.

 

Trip report: C++ On Sea 2025 -- Sandor Dargo

cpponsea2025-folkestone-to-dover.jpgAnother year, another trip report from C++ On Sea!

Trip report: C++ On Sea 2025

by Sandor Dargo

From the article:

First, a heartfelt thank-you to the organizers for inviting me to speak, and an equally big thank-you to my wife for taking care of the kids while I spent three days in Folkestone — plus a few more in London to visit the Spotify office and catch up with some bandmates.

If you have the chance, try to arrive early or stay around Folkestone for an extra day. It’s a lovely town and it’s worth exploring it. The conference program is very busy even in the evenings, so don’t count on the after hours.

This year, I arrived an half a day in advance and I had a wonderful hike from Folkestone to Dover. It was totally worth it.

In this post I’ll share:

  • Thoughts on the conference experience.
  • Highlights from talks and ideas that resonated with me.
  • Personal impressions, including reflections on my own sessions — both the main talk and the lightning talk.

A virtual destructor in C++, when? -- Andreas Fertig

2025-07-01-when-to-not-use-a-virtual-dtor-tw.pngWhen should a destructor be virtual in C++? In this post, we’ll explore a real-world example from smart pointer implementation to illustrate when virtual destructors are necessary — and when they’re not.

A virtual destructor in C++, when?

by Andreas Fertig

From the article:

In today's post, I would like to explain a design rationale used in my post Understanding the inner workings of C++ smart pointers - The shared_ptr.

Keen readers spotted that in my implementation of ctrl_blk_base, I didn't make the destructor virtual. Here is the original code for easy reference:


Reflecting JSON into C++ Objects -- Barry Revzin

C++26 marks a transformative milestone with the adoption of full compile-time reflection, enabling powerful new metaprogramming capabilities. In this post, we’ll explore how reflection lets you turn a JSON file directly into a fully-typed C++ object — all at compile time.

Reflecting JSON into C++ Objects

by Barry Revzin

From the article:

Last week, C++26 was finalized in Sofia, Bulgaria — and C++26 will include all of the reflection papers that we were pushing for:

  1. P2996R13: Reflection for C++26
  2. P3394R4: Annotations for Reflection
  3. P3293R3: Splicing a Base Class Subobject
  4. P3491R3define_static_{string,object,array}
  5. P1306R5: Expansion Statements
  6. P3096R12: Function Parameter Reflection in Reflection for C++26
  7. P3560R2: Error Handling in Reflection

Those are in the order in which they were adopted, not in the order of their impact (otherwise splicing base classes would go last). This is a pretty incredible achievement that couldn’t have happened without lots of people’s work, but no one person is more responsible for Reflection in C++26 than Dan Katz.

So today I wanted to talk about a very cool example that Dan put together on the flight home from Sofia, while I was unconscious a few seats over: the ability to, at compile time, ingest a JSON file and turn it into a C++ object. That is, given a file test.json that looks like this:

{ "outer": "text", 
"inner": { "field": "yes", "number": 2996 } 
} 

We can write this:

constexpr const char data[] = { 
     #embed "test.json" 
     , 0 

}; constexpr auto v = json_to_object<data>;

Discover C++26’s Compile-Time Reflection -- Daniel Lemire

Capture-decran-le-2025-06-21-a-21.55.10-825x510.pngC++26 is bringing a long-awaited feature to the language: compile-time reflection, enabling programs to introspect and manipulate their own structure during compilation. This powerful capability opens the door to eliminating boilerplate, improving performance, and writing more expressive, reusable code with ease.

Discover C++26’s Compile-Time Reflection

by Daniel Lemire

From the article:

Herb Sutter just announced that the verdict is in: C++26, the next version of C++, will include compile-time reflection.

Reflection in programming languages means that you have access the code’s own structure. For example, you can take a class, and enumerate its methods. For example, you could receive a class, check whether it contains a method that returns a string, call this method and get the string. Most programming languages have some form of reflection. For example, the good old Java does have complete reflection support.

However, C++ is getting compile-time reflection. It is an important development.

I announced a few months ago that thanks to joint work with Francisco Geiman Thiesen, the performance-oriented JSON library simdjson would support compile-time reflection as soon as mainstream compilers support it.

Variadic Class Template Arguments -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGVariadic templates are a powerful C++ feature that allow template classes or functions to accept an arbitrary number of parameters. In this article, we’ll explore how to combine them with class templates and examine the various ways the parameter pack can be expanded.

Variadic Class Template Arguments

by Sandor Dargo

From the article:

Let’s talk about class templates and variadic parameters. How to use them in combination?

But first of all, what are variadic templates?

Variadic template don’t accept a fixed size of parameters, but anything from one to more. The set of parameters is called the parameter pack.

In the template parameter list, we can see the three dots (...) signaling the pack after the typename or class keywords, or after the constraints. Then later in the function / constructor parameter list, you can observe it right after the actual type name, and finally once the pack is expanded, it comes after the packed variable name.

Variadic arguments can be used in so many different ways both with function and class templates. Today, we are focusing on class templates.

When you are using variadic templates with class templates, the expansion can happen at different places. You might expand the parameter pack

  • within the constructor or any other member function
  • when declaring a member variable
  • at the inheritance list
  • in a using declaration
  • in friend declarations

 

C++26: Disallow Binding a Returned Reference to a Temporary -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGThis change in C++26 tightens the rules around returning references to temporaries — and that’s a good thing. It turns dangerous, bug-prone code into immediate compilation errors, making code safer and easier to reason about. It also reflects a broader trend in modern C++: giving programmers stronger guarantees and better diagnostics, even at the cost of breaking some old patterns.

C++26: Disallow Binding a Returned Reference to a Temporary

by Sandor Dargo

From the article:

In short, thanks to P2748R5 by Brian Bi, it’s no longer possible to return a reference that binds to a temporary expression, and that’s just lovely.

What exactly is changing?

Often, a proposal modifies a lot of wording, and it’s not practical to start by reading through it all. But in this case, the changes are small and easy to digest, so let’s dive in.

This line is being removed:

“The lifetime of a temporary bound to the returned value in a function return statement (8.7.4) is not extended; the temporary is destroyed at the end of the full-expression in the return statement.”

And this line is being added (excluding the examples we’ll discuss in a moment):

“In a function whose return type is a reference, other than an invented function for std::is_convertible ([meta.rel]), a return statement that binds the returned reference to a temporary expression ([class.temporary]) is ill-formed.”

There are two interesting shifts here:

  • The language becomes more specific. It doesn’t merely mention “temporaries” but refers directly to references binding to temporary expressions, with certain exceptions.
  • The effect isn’t just that lifetime extension doesn’t happen, it’s now a compilation error. The code is ill-formed.

constexpr Functions: Optimization vs Guarantee -- Andreas Fertig

me.pngConstexpr has been around for a while now, but many don’t fully understand its subtleties. Andreas Fertig explores its use and when a constexpr expression might not be evaluated at compile time.

constexpr Functions: Optimization vs Guarantee

by Andreas Fertig

From the article:

The feature of constant evaluation is nothing new in 2023. You have constexpr available since C++11. Yet, in many of my classes, I see that people still struggle with constexpr functions. Let me shed some light on them.

What you get is not what you see

One thing, which is a feature, is that constexpr functions can be evaluated at compile-time, but they can run at run-time as well. That evaluation at compile-time requires all values known at compile-time is reasonable. But I often see that the assumption is once all values for a constexpr function are known at compile-time, the function will be evaluated at compile-time.

I can say that I find this assumption reasonable, and discovering the truth isn’t easy. Let’s consider an example (Listing 1).

constexpr auto Fun(int v)
{
  return 42 / v; ①
}

int main()
{
  const auto f = Fun(6); ②
  return f;              ③
}
The constexpr function Fun divides 42 by a value provided by the parameter v ①. In ②, I call Fun with the value 6 and assign the result to the variable f.