Articles & Books

Format your own type (Part 2) -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGPreviously, we discussed how to write our own formatter and finished with a relatively simple solution for printing a struct called ProgrammingLanguage. Today, we’ll take it to the next level.

Format your own type (Part 2)

by Sandor Dargo

From the article:

Add more options for semantic versioning

Let’s dream big. Instead of only handling major and minor versions (like Python 3.12), let’s aim to fully support semantic versioning.

Semantic versioning (SemVer) is a versioning scheme that conveys meaning about the underlying changes in a release. It typically consists of three parts: MAJOR.MINOR.PATCH.

We should be able to print all these correctly:

ProgrammingLanguage cpp{"C++", 20};
ProgrammingLanguage python312{"Python", 3, 12};
ProgrammingLanguage python31211{"Python", 3, 12, 11};


std::cout << std::format("{:%n%v} is fun", cpp) << '\n';  // C++20 is fun
std::cout << std::format("{:%n %v} is fun", python312) << '\n';  // Python 3.12 is fun
std::cout << std::format("{:%n %v} is fun", python31211) << '\n';  // Python 3.12.11 is fun

Format your own type (Part 1) -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGI recently published two posts about how C++26 improves std::format and the related facilities. (If you missed them, here are Part 1 and Part 2). Now it’s time to explore how you can format your own types using std::format.

Format your own type (Part 1)

by Sandor Dargo

From the article:

std::format was introduced in C++20 and is based on Victor Zverovich’s <fmt> library, which in turn was inspired by Python’s string formatting capabilities.

Let’s skip the fancy formatting options and simply see how to interpolate values using std::format.

#include <format>
#include <iostream>
#include <string>

int main() {
    std::string language{"C++"};
    int version{20};
    std::cout << std::format("{}{} is fun", language, version) << '\n';
}

/*
C++20 is fun
*/

That was easy.

Now imagine you want to print your own type. That won’t work by default.

A Library Approach to Constant Template Parameters -- Barry Revzin

C++26 has brought big advances, especially with reflection making its way into the working draft, but one long-standing challenge remains: supporting richer class types as constant template parameters. Although the language solution isn’t here yet, we can get surprisingly far with a library approach that uses reflection and static objects to extend what’s possible today.

A Library Approach to Constant Template Parameters

by Barry Revzin

From the article:

This library achieves two things.

First, it is just, in general, very useful. I’m hoping to make it more of a Real Library™️ once Reflection gets implemented in more than just the Bloomberg fork of Clang that Dan Katz implemented.

Second, I think it demonstrates the power of Reflection. There are so many problems that were not possible in C++23 that become solvable in C++26. We’re going to spend the next several years discovering more of those, and that makes it a pretty exciting time for C++.

 

C++26: std::format improvements (Part 2) -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGIn Part 1, we explored the improvements C++26 brings to std::format — from better to_string behavior to compile-time safety checks. In this part, we look at runtime formatting, defect fixes, and support for new types like std::filesystem::path.

C++26: std::format improvements (Part 2)

by Sandor Dargo 

From the article:

Runtime format strings

P2216R3 brought quite some improvements to std::format, including compile-time checking for format strings. Sadly, in use cases where format strings were only available at runtime, users had to go with the type-erased formatting version, std::vformat:

std::vformat(str, std::make_format_args(42));

Using two different APIs is not a great user experience, moreover, std::vformat was designed to be used by formatting function writers and not by end users. In addition, you might run into undefined behaviour, detailed in the next section.

To overcome this situation, P2918R2 adds std::runtime_format so you can mark format strings that are only available at run-time. As such you can opt out of compile-time format strings checks. This makes the API cleaner and the user code will read better as it shows better the intentions.

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>;