This week, let’s move further — shifting away from inheritance and embracing composition.
Discovering Observers - Part 3
by Sandor Dargo
From the article:
]]>You might say (and you’d be right) that publishers and subscribers can just as well be used as members instead of base classes. In fact, with our previous implementation, handling changes inside subscribers felt more complicated than necessary.
What we’d really like is this: subscribers that observe changes and trigger updates in their enclosing class in a coherent way. As one of the readers of Part 1 pointed out, this can be elegantly achieved if subscribers take callables.
Step 1: Subscribers with callables
We start by letting
Subscriberaccept astd::function, which gets called whenever the subscriber is updated:
f to std::apply, the compiler can’t peek inside the tuple to figure out which overload matches—it only sees an ambiguous callable and a single tuple argument. Because overload resolution happens before the tuple is unpacked, you need an extra layer (like a lambda) to forward the unpacked arguments and give the compiler enough information to pick the correct overload.
by Raymond Chen
From the article:
]]>Consider the following:
void f(int, int); void f(char*, char*); void test(std::tuple<int, int> t) { std::apply(f, t); // error }The compiler complains that it cannot deduce the type of the first parameter.
I’m using
std::applyhere, but the same arguments apply to functions likestd::invokeandstd::bind.From inspection, we can see that the only overload that makes sense is
f(int, int)since that is the only one that accepts two integer parameters.But the compiler doesn’t know that
std::applyis going to try to invoke its first parameter with arguments provided by the second parameter. The compiler has to choose an overload based on the information it is given in the function call.
Discovering Observers - Part 2
by Sandor Dargo
From the article:
]]>Last week, we took the observer pattern from a very simple example and evolved it into a more flexible, template-based implementation in C++. We ended up with abstracted publishers and subscribers, a templated message type for flexibility, and publishers controlling when and how updates are pushed.
This week, we’re going to tackle the challenge of supporting multiple message types in a single publisher.
First attempt: multiple inheritance of templated bases
It’s tempting to provide different specializations for our templates so the same publisher can push different message types.
The last update to the schedule for Meeting C++ 2025
by Jens Weller
From the article:
]]>With release of the static html schedule for the website everything is ready for Meeting C++ 2025!
For a few years now Meeting C++ offers two schedules: the live schedule is coming from the database, which allows us to make changes during the conference. The other schedule is part of the static website and just a single page powered by the C++ CMS from Meeting C++. Due to the 5th track this year I've just had one week before the conference the time to update the website with this now final program for the conference.
Looking at binary trees in C++
by Jens Weller
]]>From the article:
I'm in the process of preparing a quick talk on trees in C++ for Meeting C++ 2025. In order to see what the web offers, I've searched exactly for this, "trees in C++".
This showed that most posts found by duckduckgo or google were about binary trees, and in particular the same or similar implementation of using raw pointers for the left/right elements in the tree. Including using new to allocate for the nodes, only some times the code also bothers with using delete. The basic node class looks like this:
Introducing the Constexpr Debugger
by Alexander Karaev
From the article:
]]>“Not a constant expression.” You’ve seen the diagnostics and the note trail, but never the actual state. Until now.
Modern C++ pushes more logic into constexpr/consteval: parsers, tables, DSLs, hashing – real code with real branches. When code fails at compile time, you can either try to guess the reason from the compiler’s notes or de‑constexpr it and hope the runtime reproduction matches what the compiler actually did.The new Constexpr Debugger available in the first CLion 2025.3 EAP build allows you to stay in the compiler’s world and see what really happens – by stepping through evaluation, inspecting values, and confirming which if constexpr branch fired. Using it helps you understand exactly what the compiler is doing and fix issues faster.
Discovering Observers - Part 1
by Sandor Dargo
From the article:
]]>First, let’s briefly recap what the observer pattern is. It belongs to the family of behavioral design patterns.
As a reminder: design patterns are usually grouped into three categories: creational, structural, and behavioral.
You might also have encountered the observer under other names such as listener, event subscriber, or publisher-subscriber.
The central idea is simple: instead of repeatedly querying an object for information, the querying object (the observer) gets notified automatically when the information holder (the subject) changes. For example, imagine an orchestrator object that needs the latest value of a user setting. Instead of polling the setting every
nmilliseconds, it can subscribe to value changes and receive notifications whenever a new value is set.Using the common terminology: there is typically one publisher and one or more subscribers. Subscribers register for events or changes, and whenever an update happens, the publisher notifies them.
Trip Report: CppCon 2025
by Sandor Dargo
From the article:
]]>CppCon is simply bigger than any other C++ conference I’ve attended. A massive venue packed with people and sponsors. I logged more than 10,000 steps on the very first day — without ever leaving the resort or going to the gym.
The whole experience felt like it was on another scale compared to European conferences (which I also love). But then again, that’s often the impression when you see something American from a European perspective, isn’t it?
I never would have imagined a C++ conference where a live band plays while Bjarne Stroustrup himself makes final checks before stepping on stage to deliver the opening keynote. Absolutely rocks.
Structured bindings in C++17, 8 years later
by Bartlomiej Filipek
From the article:
]]>An excellent demonstration of structured bindings is an iteration through a map object.
If you have a
std::mapof elements, you might know that internally, they are stored as pairs of<const Key, ValueType>.Now, when you iterate through elements, you can do:
for (const auto& elem : myMap) { ... }You need to write
elem.firstandelem.secondto refer to the key and the value.std::map<KeyType, ValueType> myMap = getMap(); // C++14: for (const auto& elem : myMap) { // elem.first - is the key // elem.second - is the value }
You should use QPainterPath they said...
by Jens Weller
From the article:
]]>This post is about what I learned while playing around with QPainterPath for this years t-shirt at Meeting C++ 2025 sponsored by Hudson River Trading.
One of the issues from last years t-shirt was when using drawText from QPainter, one does not really *draw* text in an svg exported. Instead you'll get the text and the font kinda embedded in an svg. What good is that in a vector graphic? This was a bit of a surprise when I ran into issues with this last year during printing. While this could be solved with the printing company picking a different font, it would have been also solved by using QPainterPath. At least this was the feedback from some of the Qt experts present onsite or online...
std::map or std::unordered_map? For simplicity, we’ll refer to both containers as maps in this post.
How to Look up Values in a Map
by Sandor Dargo
From the article:
]]>Let’s explore the different options — along with their pros and cons.
operator[]Using
operator[]is the old-fashioned way to access elements of a map. It takes a key and returns a reference to the corresponding value. The complexity is log(n) forstd::mapand average constant time (with worst-case linear) forstd::unordered_map.However, there’s a big caveat.
What if the key is not present in the map?
Unlike a
vector— where accessing an invalid index withoperator[]leads to undefined behavior — amapwill instead insert a new entry with the given key and a default-constructed value. This side effect makesoperator[]unsafe for lookups where insertion is not desired.
Safely passing std::strings and std::string_view
by Niek J Bouman
From the article:
]]>Many of you will agree that C++ is a language that comes with sharp edges. One example is `std::string_view`; introduced as a type to prevent unnecessary std::string-copies, but it introduces a new footgun, namely when passing a temporary string into it:
A safe pointer in C++ that protects against use after free and updates when the pointee is moved
by Niek J. Bouman
From the article:
]]>We propose a design for a safe pointer to an object of type T that is weak in that it does not have ownership semantics, and gets notified in case the pointee is either destructed or moved.
We will pay a price at runtime for these extra guarantees in terms of a small heap-allocated state, a double pointer indirection when accessing the pointee (comparable to a virtual function call), and a check against nullptr.
The main idea of our design is to internally use a
std::shared_ptr<T*>to share ownership of a (heap-allocated) pointer T*. The ownership is shared by the pointee and allsafe_ptr<T>instances. The pointee type T must derive from the base classsafe_ptr_factory(templated on T, using the Curiously Recurring Template Pattern) with a destructor that automatically notifies the shared state about destruction by setting T* tonullptr, and with a move constructor and move assignment operator that update T* to the new this pointer (which we must properly cast withstatic_cast<T*>). The double indirection thus comes from having to dereference theshared_ptrto obtain an ordinary pointer T*, after which you must dereference once more to access the pointee. You might recognize an instance of Gang-of-Four’s observer pattern in our design.
Linus Torvalds and the Supposedly “Garbage Code”
by Giovanni Dicanio
From the article:
]]>So, the correct explicit code is not something as simple as “(a << 16) + b”.
[...] As you can see, the type casts, the parentheses, the potential bit-masking, do require attention. But once you get the code right, you can safely and conveniently reuse it every time you need!
CppCon 2025 Trip Report
by tipi.build by EngFlow
About the report
]]>tipi.build by EngFlow attended both as a developer team and as a CppCon sponsor. Discover in our trip report the highlights from the sessions we attended and the talks we gave, How monday’s afternoon break started with ice cream + key takeaways and resources if you’d like to dive deeper.
remove_cvref_t on our template parameters before applying concepts to them. We also saw that the solution is not super readable because we lose access to the terse, shorthand syntax.
C++26: Concept and variable-template template-parameters
by Sandor Dargo
From the article:
]]>C++ already allows passing templates as template parameters, but only if they are class templates. A common reason for doing this is to allow higher-level abstractions. For instance, you may want to pass in a container template like
std::vector, without specifying the type it contains.Jason Turner explains this well in C++ Weekly - Ep 368 - The Power of template-template Parameters: A Basic Guide, but here’s his example for quick reference:
template<template <typename Contained, typename Alloc = std::allocator<Contained>> typename ResultType> auto get_data() { ResultType<double> result; // ... return result; } int main() { auto data = get_data<std::vector>(); }
Use concepts with std::remove_cvref_t
by Sandor Dargo
From the article:
]]>By now, it’s well known that using unconstrained templates is discouraged. Even the C++ Core Guidelines strongly recommend against it.
T.47 only advises avoiding highly visible unconstrained templates with common names due to the risks of argument-dependent lookup going wrong. T.10 goes further, recommending that we specify concepts for every template argument to improve both simplicity and readability.
The same idea appears in I.9, which suggests documenting template parameters using concepts.
It’s hard to argue with these guidelines. Concepts make code more readable — just by looking at a function, class, or variable template, the reader can immediately tell what kinds of types are accepted.
If you want to learn more about concepts, check out my concepts-related articles or my book on concepts.
But what makes a good concept? That’s a more complex topic — and one we can’t fully cover in a single article.
Simple Compile-Time Dynamic Programming in Modern C++
by Andrew Drakeford
From the article:
]]>Modern C++ enables us to solve mathematical optimisation problems at compile time. With the expanded constexpr capabilities [Fertig21, Turner18, Turner19, Wu24], we can now write clear and efficient optimisation logic that runs during compilation. Fixed-size containers such as
std::arrayfit naturally into these routines. Even standard algorithms, such asstd::sortandstd::lower_bound, are now constexpr, enabling more straightforward code and more powerful compile-time computations. Additionally, compile-time optimisation generates constant results, which enables the compiler to create even more efficient code. We will use the matrix chain multiplication problem as our worked example.Matrix chain multiplication
Matrix chain multiplication is a classic dynamic programming problem [Corman22, Das19, Mount]. It aims to determine the most efficient method for multiplying a sequence of matrices. Since matrix multiplication is associative, the order of grouping does not affect the result. However, the number of scalar multiplications involved can vary depending on the grouping.
Consider the three matrices A₁ (10×100), A₂ (100×5), and A₃ (5×50), multiplied in a chain, A₁ × A₂ × A₃.
There are two ways to multiply them:
- Grouping as (A₁ × A₂) × A₃ first computes a 10×5 matrix, then multiplies that with A₃. This results in 5,000 operations for the first multiplication, and another 2,500 for the second – a total of 7,500 scalar multiplications.
- Grouping as A₁ × (A₂ × A₃) first multiplies A₂ and A₃, then A₁. This results in 25,000 operations for the first step and 50,000 for the second – a total of 75,000, which is clearly worse.
C++26 reflection at compile-time
by Andreas Fertig
From the article:
]]>While the new standard will have plenty of great improvements the one that will most likely change a lot is reflection at compile-time! In Sofia we voted seven reflection papers into C++26:
- P1306R5 Expansion statements
- P2996R13 Reflection for C++26
- P3096R12: Function parameter reflection in reflection for C++26
- P3293R3: Splicing a base class subobject
- P3394R4: Annotations for reflection
- P3491R3: define_static_
- P3560R2: Error handling in reflection
The papers above should give you enough to read for your vacation. I'll leave that theoretical study up to you for now.
Let's talk practical
The main question is, what can you do with that new feature? Well, I'm not the first one who published their ideas.
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
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::formatwas 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
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++.
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::vformatwas 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_formatso 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.
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_stringandstd::to_wstringusestd::formatP2587R3 by Victor Zverovich proposes replacing
sprintfwithstd::formatin the arithmetic overloads ofstd::to_stringandstd::to_wstring.The motivation?
std::to_stringhas long been known to produce not-so-great and misleading results (differing fromiostreams), especially with floating-point values.std::to_stringuses 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.420000These outputs are imprecise and often unnecessary. By leveragingstd::format(and ultimatelystd::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]]>One new library and updates to 28 more.
Bloom, configurable filters for probabilistic lookup: https://boost.org/libs/bloom
]]>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_castand I discouraged you from using it. In general, it makes code worse in terms of readability. When you get rid ofdynamic_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_castThey 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
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?
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 destructorvirtual. Here is the original code for easy reference:
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:
- P2996R13: Reflection for C++26
- P3394R4: Annotations for Reflection
- P3293R3: Splicing a Base Class Subobject
- P3491R3:
define_static_{string,object,array}- P1306R5: Expansion Statements
- P3096R12: Function Parameter Reflection in Reflection for C++26
- 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.jsonthat 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
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
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 thetypenameorclasskeywords, 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
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
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
constexprfunctions. Let me shed some light on them.What you get is not what you see
One thing, which is a feature, is that
constexprfunctions 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 aconstexprfunction 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; ③ }TheconstexprfunctionFundivides 42 by a value provided by the parameterv①. In ②, I callFunwith the value6and assign the result to the variablef.
Three types of name lookups in C++
by Sandor Dargo
From the article:
]]>Let’s get back to some basics this week and talk about name lookups in C++. In other words: when you refer to a symbol in your code, how does the compiler find it?
Essentially, we can differentiate between three kinds of lookups:
- Qualified name lookup
- Unqualified name lookup
- Argument-Dependent Lookup (ADL)
Let’s explore them in that order.
Qualified Name Lookup
The term qualified refers to symbols that are explicitly scoped using the
::operator. In other words, these are names that appear to the right of a::, such asxina::b::x.Before the compiler can perform a qualified name lookup, it must first resolve the left-hand side of the
::operator. This identifies the namespace or class being referenced.Qualified name lookup is relatively simple: it only searches the explicitly named scope. It does not search enclosing or outer scopes.
std::is_copy_constructible. However, whether that constructor is instantiable is a separate matter—if it attempts to call a deleted base copy constructor, you'll still get a compile-time error when you actually try to use it.
Why does C++ think my class is copy-constructible when it can’t be copy-constructed?
by Raymond Chen
From the article:
]]>Consider the following scenario:
template<typename T>
struct Base
{
// Default-constructible
Base() = default;// Not copy-constructible
Base(Base const &) = delete;
};template<typename T>
struct Derived : Base<T>
{
Derived() = default;
Derived(Derived const& d) : Base<T>(d) {}
};// This assertion passes?
static_assert(
std::is_copy_constructible_v<Derived<int>>);
Why does this assertion pass? It is plainly evident that you cannot copy a Derived<int> because doing so will try to copy the Base<int>, which is not copyable.
std::tuple, structured bindings, std::expected, and std::optional, handling multiple return values—and even error codes—has become both clean and expressive.
Returning several values from a function in C++ (C++23 edition)
by Daniel Lemire
From the article:
]]>Many programming languages such as the Go programming language are designed to make it easy to return several values at once from a function. In Go, it is often used to return an optional error code. The C++ programming language does not have a built-in support for returning several values. However, several standard types can serve the same purpose. If you need to return two values, you can use an std::pair instance. If you need to return two or more values, an std::tuple instance will do. With recent C++ standards, it works really well!
Suppose we want to compute a division with a string error message when one is trying to divided by zero:
std::tuple<int,std::string> divide(int a, int b) { if (b == 0) { return {0, "Error: Division by zero"}; } return {a / b, "Success"}; }This approach works nicely. The code is clear and readable.
You might be concerned that we are fixing the type (int). If you want to write one function for all integer types, you can do so with concepts, like so:
std::from_range tag, a range and an optional allocator. These from_range constructors make it easier to construct containers from ranges, helping make C++ code more concise, more expressive, and less error-prone.
Constructing Containers from Ranges in C++23
by Sandor Dargo
From the article:
]]>I’ve written plenty on this blog about standard algorithms, but far less about ranges. That’s mostly because, although I’ve had production-ready compilers with C++20 ranges since late 2021, the original ranges library lacked a few key capabilities.
The biggest gap was at the end of a pipeline: you could transform data lazily, but you couldn’t drop the result straight into a brand-new container. What you got back was a view; turning that view into, say, a
std::vectorstill required the old iterator-pair constructor.C++23 fixes that in two complementary ways:
std::to(an adaptor that finishes a pipeline by converting to a container), andfrom_rangeconstructors on every standard container.Today we’ll focus on the second improvement, because it’s the one you can implement in your own types, too.
The
from_rangeconstructorEvery standard container now supports a new set of constructors that make integration with ranges smoother — the so-called
from_rangeconstructors.These constructors allow you to build a container directly from a range, rather than from a pair of iterators.
C++ Insights now uses Clang 20
by Andreas Fertig
From the article:
]]>
size_tFor a long time now, when you used
size_torstd::size_tthe resulting transformation kept the name. It did not expand to the underlying machine-specific date type. To be honest, that was more like a happy accident. Clang 20 came with two changes to libc++The first https://github.com/llvm/llvm-project/commit/d6832a611a7c4ec36f08b1cfe9af850dad32da2e modularized
<cstddef>for better internal structuring, avoiding too much content to be included. This patch was followed by a second one: https://github.com/llvm/llvm-project/commit/5acc4a3dc0e2145d2bfef47f1543bb291c2b866a. This one now made an interesting change.Previously, libc++ defined
std::size_tas1using ::size_t _LIBCPP_USING_IF_EXISTS;As the second patch highlighted, this required including the operating systems
<stddef.h>. In the spirit of reducing unnecessary includes the line was changed to:1using size_t = decltype(sizeof(int));This is an easy C++ solution to get the proper data type for
size_t. Which is great. Yet, the AST nodes of the two versions look different. Previously, the operating system (macOS in this case) defined in its header:1typedef unsigned long size_t;Well, with the new version, the transformation no longer stops at
size_tbut expands it all down tounsigned long. This probably should have been the case from the beginning, but I liked that tests and transformations did not change across platforms in this specific case. However, there are other instances where the transformation did yield different output on different platforms, so I accept this one.
What’s New for C++ Developers in Visual Studio 2022 17.14
by Sy Brand
From the article:
We’ve made a myriad of fixes and improvements to the MSVC compiler and standard library. See C++ Language Updates in MSVC in Visual Studio 2022 17.14 for a full list of changes on the compiler side, and the STL Changelog for all the standard library updates.
Compiler
We’ve added support for several C++23 features, which are available under the
/std:c++latestand/std:c++23previewflags.You can now omit
auto lambda = [] constexpr { }; //no '()' needed after the capture list()in some forms of lambdas that previously required them, thanks to P1102R2:
We implemented if consteval , with which you can run different code depending on whether the statement is executed at compile time or run time. This is useful for cases where your run time version can be heavily optimized with compiler intrinsics or inline assembly that are not available at compile time:
constexpr size_t strlen(char const* s) {]]>
if consteval {
// if executed at compile time, use a constexpr-friendly algorithm
for (const char *p = s; ; ++p) {
if (*p == '0円') {
return static_cast<std::size_t>(p - s);
}
}
} else {
// if executed at run time, use inline assembly
__asm__("SSE 4.2 magic");
}
}
C++26: Erroneous Behaviour
by Sandor Dargo
From the article:
]]>If you pick a random talk at a C++ conference these days, there is a fair chance that the speaker will mention safety at least a couple of times. It’s probably fine like that. The committee and the community must think about improving both the safety situation and the reputation of C++.
If you follow what’s going on in this space, you are probably aware that people have different perspectives on safety. I think almost everybody finds it important, but they would solve the problem in their own way.
A big source of issues is certain manifestations of undefined behaviour. It affects both the safety and the stability of software. I remember that a few years ago when I was working on some services which had to support a 10× growth, one of the important points was to eliminate undefined behaviour as much as possible. One main point for us was to remove uninitialized variables which often lead to crashing services.
Thanks to P2795R5 by Thomas Köppe, uninitialized reads won’t be undefined behaviour anymore – starting from C++26. Instead, they will get a new behaviour called ‘erroneous behaviour’.
The great advantage of erroneous behaviour is that it will work just by recompiling existing code. It will diagnose where you forgot to initialize variables. You don’t have to systematically go through your code and let’s say declare everything as auto to make sure that every variable has an initialized value. Which you probably wouldn’t do anyway.
Writing Senders
by Lucian Radu Teodorescu
From the article:
]]>If people are just using frameworks based on
std::execution, they mainly need to care about senders and schedulers. These are user-facing concepts. However, if people want to implement sender-ready abstractions, they also need to consider receivers and operation states – these are implementer-side concepts. As this article mainly focuses on the implementation of sender abstractions, we need to discuss these two concepts in more detail.A receiver is defined in P2300 as “a callback that supports more than one channel” [P2300R10]. The proposal defines a concept for a receiver, unsurprisingly called
receiver. To model this concept, a type needs to meet the following conditions:
- It must be movable and copyable.
- It must have an inner type alias named
receiver_conceptthat is equal toreceiver_t(or a derived type).std::execution::get_env()must be callable on an object of this type (to retrieve the environment of the receiver).A receiver is the object that receives the sender’s completion signal, i.e., one of
set_value(),set_error(), orset_stopped(). As explained in the December 2024 issue [Teodorescu24], a sender may have different value completion types and different error completion types. For example, the same sender might sometimes complete withset_value(int, int), sometimes withset_value(double), sometimes withset_error(std::exception_ptr), sometimes withset_error(std::error_code), and sometimes withset_stopped(). This implies that a receiver must also be able to accept multiple types of completion signals.
constexpr in C++26. Those articles weren’t exhaustive — I deliberately left out one major topic: exceptions.
SANDOR_DARGO_ROUND.JPGStarting with C++26, it will become possible to throw exceptions during constant evaluation. This capability is enabled through both language and library changes. Given the significance of this feature, it deserves its own dedicated post.
C++26: constexpr Exceptions
by Sandor Dargo
From the article:
]]>P3068R6: Allowing exception throwing in constant-evaluation
The proposal for static reflection suggested allowing exceptions in constant-evaluated code, and P3068R6 brings that feature to life.
constexprexceptions are conceptually similar toconstexprallocations. Just as aconstexpr stringcan’t escape constant evaluation and reach runtime,constexprexceptions also have to remain within compile-time code.Previously, using
throwin aconstexprcontext caused a compilation error. With C++26, such code can now compile — unless an exception is actually thrown and left uncaught, in which case a compile-time error is still issued. But the error now provides more meaningful diagnostics.
An option(al) to surprise you
by Andreas Fertig
From the article:
]]>The base
What I will show you is a much down-stripped and, of course, altered version. It was about a message system, but that's not important. Have a look at the code below.
2025年05月09日_14-05-45.png
You can see a class enum for a state and a functionWorker. The function takes aStateand aconst char*message nameddata. The function's job is to create astd::optionalcontaining the user data, a C-style string.
MultiArrayList—offered a compelling real-world example. Inspired by that, this post explores how we can achieve a similar “struct-of-arrays” approach in C++26 using reflection to build a SoaVector<T> that separates member storage for improved memory locality and performance.
Implementing a Struct of Arrays
by Barry Revzin
From the article:
Recently, I watched Andrew Kelley’s talk on Practical Data Oriented Design. It goes into some of the architectural changes he’s been making to the Zig compiler, with pretty significant performance benefit. Would definitely recommend checking out the talk, even if you’re like me and have never written any Zig.
About halfway through the talk, he shows a way to improve his memory usage by avoiding wasting memory. By turning this structure:
const Monster = struct { anim : *Animation, kind : Kind, const Kind = enum { snake, bat, wolf, dingo, human }; }; var monsters : ArrayList(Monster) = .{};
]]>into this one:
var monsters : MultiArrayList(Monster) = .{};
ArrayList(Monster)is what we could callstd::vector<Monster>, andMultiArrayList(Monster)now stores theanims andkinds in two separate arrays, instead of one. That is, a struct of arrays instead of an array of structs. But it’s a tiny code change.
Trip report: June 2025 ISO C++ standards meeting (Sofia, Bulgaria)
by Herb Sutter
From the article:
]]>c26-reflection.pngA unique milestone: “Whole new language”
Today marks a turning point in C++: A few minutes ago, the C++ committee voted the first seven (7) papers for compile-time reflection into draft C++26 to several sustained rounds of applause in the room. I think Hana “Ms. Constexpr” Dusíková summarized the impact of this feature best a few days ago, in her calm deadpan way… when she was told that the reflection paper was going to make it to the Saturday adoption poll, she gave a little shrug and just quietly said: “Whole new language.”
Mic drop.
C++20 Concepts for Nicer Compiler Errors
by Daniel Lemire
From the article:
]]>In C++, templates enable generic programming by allowing functions and classes to operate on different data types without sacrificing type safety. Defined using the template keyword, they let developers write reusable, type-agnostic code, such as functions (e.g., template <typename T> max(T a, T b)) or classes (e.g., std::vector), where the type T is specified at compile time.
Historically, the C++ language has tended to produce complicated compiler error messages. The main culprit is template metaprogramming. C++ templates are powerful but complex. When errors occur in template code, the compiler generates long, verbose messages with nested type information, often involving deep template instantiations. A simple mistake in a template function can produce a message spanning multiple lines with obscure type names.
Let us consider an example. In C++, we often use the ‘Standard Template Library (STL)’. It includes a useful dynamic array template: std::vector. A vector manages a sequence of elements with automatic memory handling and flexible sizing. Unlike fixed-size arrays, it can grow or shrink at runtime through operations like push_back to append elements or pop_back to remove them. You can store just about anything in an std::vector but there are some limits. For example, your type must be copyable.
C++26: More constexpr in the Standard Library
by Sandor Dargo
From the article:
]]>P2562R1:
constexprstable sortingThis paper proposes making
std::stable_sort,std::stable_partition,std::inplace_merge, and theirrangescounterparts usable in constant expressions. While many algorithms have becomeconstexprover the years, this family related to stable sorting had remained exceptions — until now.The recent introduction of
constexprcontainers gives extra motivation for this proposal. If you can construct a container at compile time, it’s only natural to want to sort it there, too. More importantly, aconstexpr std::vectorcan now support efficient, stable sorting algorithms.A key question is whether the algorithm can meet its computational complexity requirements under the constraints of constant evaluation. Fortunately,
std::is_constant_evaluated()provides an escape hatch for implementations. For deeper details, check out the proposal itself.
task_ sequencer class for running asynchronous operations in sequence. There’s a problem with the implementation of QueueTaskAsync: What happens if an exception occurs?
Fixing Exception Safety in our
task_sequencerby Raymond Chen
From the article:
Let’s look at the various places an exception can occur in
QueueTaskAsync.template<typename Maker> auto QueueTaskAsync(Maker&& maker) ->decltype(maker()) { auto current = std::make_shared<chained_task>(); auto previous = [&] { winrt::slim_lock_guard guard(m_mutex); return std::exchange(m_latest, current); ← oops }(); suspender suspend; using Async = decltype(maker()); auto task = [](auto&& current, auto&& makerParam, auto&& contextParam, auto& suspend) -> Async { completer completer{ std::move(current) }; auto maker = std::move(makerParam); auto context = std::move(contextParam); co_await suspend; co_await context; co_return co_await maker(); }(current, std::forward<Maker>(maker), winrt::apartment_context(), suspend); previous->continue_with(suspend.handle); return task; }
]]>If an exception occurs at
make_, then no harm is done because we haven’t done anything yet.shared If an exception occurs when starting the lambda task, then we are in trouble. We have already linked the
currentontom_latest, but we will never callcontinue_, so the chain of tasks stops making progress.with() To fix this, we need to delay hooking up the
currentto the chain ofchained_s until we are sure that we have a task to chain.task
concat_view, join_view, and join_with_view—exploring their differences, use cases, and practical examples.
How to Join or Concat Ranges, C++26
by Bartlomiej Filipek
From the article:
]]>Modern C++ continuously improves its range library to provide more expressive, flexible, and efficient ways to manipulate collections. Traditionally, achieving tasks like concatenation and flattening required manual loops, copying, or custom algorithms. With C++’s range adaptors, we now have an elegant and efficient way to process collections lazily without unnecessary allocations.
In this post, we will explore three powerful range adaptors introduced in different C++ standards:
std::ranges::concat_view(C++26)std::ranges::join_view(C++20)std::ranges::join_with_view(C++23)Let’s break down their differences, use cases, and examples.
std::ranges::concat_view(C++26)The
concat_viewallows you to concatenate multiple independent ranges into a single sequence. Unlikejoin_view, it does not require a range of ranges—it simply merges the given ranges sequentially while preserving their structure.In short:
- Takes multiple independent ranges as arguments.
- Supports random access if all underlying ranges support it.
- Allows modification if underlying ranges are writable.
- Lazy evaluation: No additional memory allocations.
Widget and a string literal, only to be met with confusing compiler errors that hinted at deeper quirks in C++'s type deduction and function template specialization rules.
Function overloading is more flexible (and more convenient) than template function specialization
by Raymond Chen
From the article:
]]>A colleague of mine was having trouble specializing a templated function. Here’s a simplified version.
template<typename T, typename U> bool same_name(T const& t, U const& u) { return t.name() == u.name(); }They wanted to provide a specialization for the case that the parameters are a Widget and a string literal.
template<> bool same_name<Widget, const char[]>(Widget const& widget, const char name[]) { return strcmp(widget.descriptor().name().c_str(), name) == 0; }However, this failed to compile:
// msvc error C2912: explicit specialization 'bool same_name<Widget,const char[]>(const Widget &,const char [])' is not a specialization of a function templateWhat do you mean “not a specialization of a function template”? I mean doesn’t it look like a specialization of a function template? It sure follows the correct syntax for a function template specialization.