<![CDATA[Standard C++ | Articles & Books]]> http://isocpp.org/blog en Copyright 2025 Structured Bindings in C++17, 8 Years Later -- Bartlomiej Filipek https://isocpp.org//blog/2025/10/structured-bindings-in-cpp17-8-years-later-bartlomiej-filipek https://isocpp.org//blog/2025/10/structured-bindings-in-cpp17-8-years-later-bartlomiej-filipek Filipek-structuredbindings.pngStructured binding is a C++17 feature that allows you to bind multiple variables to the elements of a structured object, such as a tuple or struct. This can make your code more concise and easier to read, especially when working with complex data structures. On this blog, we already covered this functionality, but we’ll talk about some good C++26 additions and real code use cases.

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::map of 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.first and elem.second to 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 
}

 

]]>
Thu, 09 Oct 2025 19:43:16 +0000 Blog Staff
You should use QPainterPath they said... https://isocpp.org//blog/2025/10/you-should-use-qpainterpath-they-said https://isocpp.org//blog/2025/10/you-should-use-qpainterpath-they-said A blog entry about this years t-shirt at Meeting C++ 2025 and exploring QPainterPath for it.

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

 

]]>
Wed, 08 Oct 2025 17:22:39 +0000 Meeting C++
How to Look up Values in a Map -- Sandor Dargo https://isocpp.org//blog/2025/10/how-to-look-up-values-in-a-map-sandor-dargo https://isocpp.org//blog/2025/10/how-to-look-up-values-in-a-map-sandor-dargo SANDOR_DARGO_ROUND.JPGWhether you’re in a coding interview or writing production code, you’ll eventually face the question: What’s the right way to look up values in a 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) for std::map and average constant time (with worst-case linear) for std::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 with operator[] leads to undefined behavior — a map will instead insert a new entry with the given key and a default-constructed value. This side effect makes operator[] unsafe for lookups where insertion is not desired.

]]>
Wed, 01 Oct 2025 19:39:59 +0000 Blog Staff
Safely passing strings and string_views -- Niek J Bouman https://isocpp.org//blog/2025/09/safely-passing-strings-and-string_views https://isocpp.org//blog/2025/09/safely-passing-strings-and-string_views Passing a string temporary into a string_view can make the latter dangling 

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:

]]>
Sat, 27 Sep 2025 21:01:08 +0000 niekb
A safer C++ pointer class -- Niek J. Bouman https://isocpp.org//blog/2025/09/a-safer-cpp-pointer-class-niek-bouman https://isocpp.org//blog/2025/09/a-safer-cpp-pointer-class-niek-bouman Sometimes some object A needs to interact with another object B, e.g., A calls one of B’s methods. In a language like C++, it is left to the programmer to assure that B outlives A; if B happens to be already destructed, this would be a use-after-free bug. Managing object lifetimes can be tricky, especially with asynchronous code.

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 all safe_ptr<T> instances. The pointee type T must derive from the base class safe_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* to nullptr, and with a move constructor and move assignment operator that update T* to the new this pointer (which we must properly cast with static_cast<T*>). The double indirection thus comes from having to dereference the shared_ptr to 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.

]]>
Sat, 27 Sep 2025 20:59:03 +0000 niekb
Linus Torvalds and the Supposedly Garbage Code -- Giovanni Dicanio https://isocpp.org//blog/2025/09/linus-torvalds-and-the-supposedly-garbage-code-giovanni-dicanio https://isocpp.org//blog/2025/09/linus-torvalds-and-the-supposedly-garbage-code-giovanni-dicanio Some reflections on a harsh critic by Linus Torvalds on a RISC-V Linux kernel contribution. 

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!

 

]]>
Sat, 27 Sep 2025 20:54:24 +0000 Giovanni Dicanio
CppCon 2025 Trip Report – tipi.build by EngFlow https://isocpp.org//blog/2025/09/cppcon-2025-trip-report-tipi.build-by-engflow https://isocpp.org//blog/2025/09/cppcon-2025-trip-report-tipi.build-by-engflow CppCon 2025 was packed with exciting talks, deep dives, and great conversations.

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.

]]>
Sat, 27 Sep 2025 20:50:20 +0000 daminetreg
C++26: Concept and variable-template template-parameters -- Sandor Dargo https://isocpp.org//blog/2025/09/cpp26-concept-and-variable-template-template-parameters-sandor-dargo https://isocpp.org//blog/2025/09/cpp26-concept-and-variable-template-template-parameters-sandor-dargo SANDOR_DARGO_ROUND.JPGLast week, we discussed why we should sometimes use 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>();
}
]]>
Thu, 25 Sep 2025 22:20:21 +0000 Blog Staff
Use concepts with std::remove_cvref_t -- Sandor Dargo https://isocpp.org//blog/2025/09/use-concepts-with-stdremove-cvref-t-sandor-dargo https://isocpp.org//blog/2025/09/use-concepts-with-stdremove-cvref-t-sandor-dargo SANDOR_DARGO_ROUND.JPGLet’s talk about templates, constraints, and concepts. We’ll start with a quick reminder of why concepts are essential when working with templates. Then we’ll dive into the challenge posed by reference-qualified types and finish with a practical solution.

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.

]]>
Tue, 23 Sep 2025 22:17:57 +0000 Blog Staff
Simple Compile-Time Dynamic Programming in Modern C++ -- Andrew Drakeford https://isocpp.org//blog/2025/09/simple-compile-time-dynamic-programming-in-modern-cpp-andrew-drakeford https://isocpp.org//blog/2025/09/simple-compile-time-dynamic-programming-in-modern-cpp-andrew-drakeford logo.pngCompile time code can be very efficient. Andrew Drakeford demonstrates how to write efficient chains of matrix multiplication.

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::array fit naturally into these routines. Even standard algorithms, such as std::sort and std::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:

  1. 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.
  2. 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.
]]>
Fri, 19 Sep 2025 22:15:15 +0000 Blog Staff
C++26 reflection at compile-time -- Andreas Fertig https://isocpp.org//blog/2025/09/cpp26-reflection-at-compile-time-andreas-fertig https://isocpp.org//blog/2025/09/cpp26-reflection-at-compile-time-andreas-fertig 797f4c8c0b89b22b.pngIn today's post, I like to talk about C++26 and one of the probably most impactful features that have been added to the working draft. While C++26 is still some months away from official completion, since the WG21 summer meeting in June we all now know what will be in C++26.

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.

]]>
Wed, 17 Sep 2025 22:10:14 +0000 Blog Staff
Format your own type (Part 2) -- Sandor Dargo https://isocpp.org//blog/2025/09/format-your-own-type-part-2-sandor-dargo https://isocpp.org//blog/2025/09/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
]]>
Mon, 15 Sep 2025 22:07:32 +0000 Blog Staff
Format your own type (Part 1) -- Sandor Dargo https://isocpp.org//blog/2025/09/format-your-own-type-part-1-sandor-dargo https://isocpp.org//blog/2025/09/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.

]]>
Thu, 11 Sep 2025 03:02:43 +0000 Blog Staff
A Library Approach to Constant Template Parameters -- Barry Revzin https://isocpp.org//blog/2025/09/a-library-approach-to-constant-template-parameters-barry-revzin https://isocpp.org//blog/2025/09/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++.

 

]]>
Thu, 04 Sep 2025 21:56:05 +0000 Blog Staff
C++26: std::format improvements (Part 2) -- Sandor Dargo https://isocpp.org//blog/2025/09/cpp26-stdformat-improvements-part-2-sandor-dargo https://isocpp.org//blog/2025/09/cpp26-stdformat-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.

]]>
Tue, 02 Sep 2025 21:55:00 +0000 Blog Staff
C++26: std::format improvement (Part 1) -- Sandor Dargo https://isocpp.org//blog/2025/08/cpp26-stdformat-improvement-part-1-sandor-dargo https://isocpp.org//blog/2025/08/cpp26-stdformat-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
]]>
Fri, 29 Aug 2025 21:55:35 +0000 Blog Staff
Boost version 1.89 released! https://isocpp.org//blog/2025/08/boost-version-1.89-released https://isocpp.org//blog/2025/08/boost-version-1.89-released space.pngspace.pnggetboost.pngRelease 1.89 of the Boost C++ Libraries is now available.

One new library and updates to 28 more.

Bloom, configurable filters for probabilistic lookup: https://boost.org/libs/bloom

]]>
Wed, 27 Aug 2025 21:51:14 +0000 Blog Staff
Once More About dynamic_cast, a Real Use Case -- Sandor Dargo https://isocpp.org//blog/2025/08/once-more-about-dynamic-cast-a-real-use-case-sandor-dargo https://isocpp.org//blog/2025/08/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.

 

]]>
Thu, 21 Aug 2025 15:14:18 +0000 Blog Staff
Trip report: C++ On Sea 2025 -- Sandor Dargo https://isocpp.org//blog/2025/08/trip-report-cpp-on-sea-2025-sandor-dargo https://isocpp.org//blog/2025/08/trip-report-cpp-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.
]]>
Tue, 19 Aug 2025 14:11:51 +0000 Blog Staff
A virtual destructor in C++, when? -- Andreas Fertig https://isocpp.org//blog/2025/08/a-virtual-destructor-in-cpp-when-andreas-fertig https://isocpp.org//blog/2025/08/a-virtual-destructor-in-cpp-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:


]]>
Fri, 15 Aug 2025 15:05:43 +0000 Blog Staff
Reflecting JSON into C++ Objects -- Barry Revzin https://isocpp.org//blog/2025/08/reflecting-json-into-cpp-objects-barry-revzin https://isocpp.org//blog/2025/08/reflecting-json-into-cpp-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. P3491R3: define_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>;
]]>
Wed, 13 Aug 2025 16:00:45 +0000 Blog Staff
Discover C++26’s Compile-Time Reflection -- Daniel Lemire https://isocpp.org//blog/2025/08/discover-cpp26s-compile-time-reflection-daniel-lemire https://isocpp.org//blog/2025/08/discover-cpp26s-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.

]]>
Sat, 09 Aug 2025 16:54:09 +0000 Blog Staff
Variadic Class Template Arguments -- Sandor Dargo https://isocpp.org//blog/2025/08/variadic-class-template-arguments-sandor-dargo https://isocpp.org//blog/2025/08/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

 

]]>
Tue, 05 Aug 2025 15:50:40 +0000 Blog Staff
C++26: Disallow Binding a Returned Reference to a Temporary -- Sandor Dargo https://isocpp.org//blog/2025/07/cpp26-disallow-binding-a-returned-reference-to-a-temporary-sandor-dargo https://isocpp.org//blog/2025/07/cpp26-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.
]]>
Fri, 25 Jul 2025 21:58:23 +0000 Blog Staff
constexpr Functions: Optimization vs Guarantee -- Andreas Fertig https://isocpp.org//blog/2025/07/constexpr-functions-optimization-vs-guarantee-andreas-fertig1 https://isocpp.org//blog/2025/07/constexpr-functions-optimization-vs-guarantee-andreas-fertig1 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.
]]>
Wed, 23 Jul 2025 21:54:53 +0000 Blog Staff
Three types of name lookups in C++ -- Sandor Dargo https://isocpp.org//blog/2025/07/three-types-of-name-lookups-in-cpp-sandor-dargo https://isocpp.org//blog/2025/07/three-types-of-name-lookups-in-cpp-sandor-dargo SANDOR_DARGO_ROUND.JPGLet's revisit a core concept in C++: how the compiler finds the names you use in your code. From qualified and unqualified name lookups to the special case of Argument-Dependent Lookup (ADL), understanding these mechanisms is essential for writing clear and correct C++ programs.

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 as x in a::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.

]]>
Mon, 21 Jul 2025 21:51:07 +0000 Blog Staff
Why does C++ think my class is copy-constructible when it can’t be copy-constructed? -- Raymond Chen https://isocpp.org//blog/2025/07/why-does-cpp-think-my-class-is-copy-constructible-when-it-cant-be-copy-cons https://isocpp.org//blog/2025/07/why-does-cpp-think-my-class-is-copy-constructible-when-it-cant-be-copy-cons RaymondChen_5in-150x150.jpgIn C++, the presence of a user-declared (but not explicitly deleted) copy constructor is enough for the type to be considered copy-constructible by traits like 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.

]]>
Thu, 17 Jul 2025 21:48:04 +0000 Blog Staff
Returning several values from a function in C++ (C++23 edition) -- Daniel Lemire https://isocpp.org//blog/2025/07/returning-several-values-from-a-function-in-cpp-c23-edition-daniel-lemire https://isocpp.org//blog/2025/07/returning-several-values-from-a-function-in-cpp-c23-edition-daniel-lemire RkWx2Fr8_400x400.jpgWhile C++ doesn’t have native syntax for returning multiple values like some other languages, modern C++ offers powerful tools to accomplish the same goal. With features like 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:

]]>
Tue, 15 Jul 2025 21:44:07 +0000 Blog Staff
Constructing Containers from Ranges in C++23 -- Sandor Dargo https://isocpp.org//blog/2025/07/constructing-containers-from-ranges-in-cpp23-sandor-dargo https://isocpp.org//blog/2025/07/constructing-containers-from-ranges-in-cpp23-sandor-dargo SANDOR_DARGO_ROUND.JPGStarting from C++23, standard containers support a new set of constructor overloads. These constructors take a 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::vector still 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), and
  • from_range constructors 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_range constructor

Every standard container now supports a new set of constructors that make integration with ranges smoother — the so-called from_range constructors.

These constructors allow you to build a container directly from a range, rather than from a pair of iterators.

]]>
Fri, 11 Jul 2025 21:38:53 +0000 Blog Staff
C++ Insights now uses Clang 20 -- Andreas Fertig https://isocpp.org//blog/2025/07/cpp-insights-now-uses-clang-20-andreas-fertig https://isocpp.org//blog/2025/07/cpp-insights-now-uses-clang-20-andreas-fertig me.pngTime flies—C++ Insights just turned 7! To celebrate, I’ve upgraded the tool to Clang 20, unlocking even more C++23 and C++26 features for you to explore.

C++ Insights now uses Clang 20

by Andreas Fertig

From the article:

size_t

For a long time now, when you used size_t or std::size_t the 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_t as

1
using ::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:

1
using 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:

1
typedef unsigned long size_t; 

Well, with the new version, the transformation no longer stops at size_t but expands it all down to unsigned 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.

 

]]>
Wed, 09 Jul 2025 21:35:32 +0000 Blog Staff
What’s New for C++ Developers in Visual Studio 2022 17.14 -- Sy Brand https://isocpp.org//blog/2025/07/whats-new-for-cpp-developers-in-visual-studio-2022-17.14-sy-brand https://isocpp.org//blog/2025/07/whats-new-for-cpp-developers-in-visual-studio-2022-17.14-sy-brand RE1Mu3b.pngVisual Studio 2022 version 17.14 is now generally available! This post summarizes the new features you can find in this release for C++. You can download Visual Studio 2022 from the Visual Studio downloads page or upgrade your existing installation by following the Update Visual Studio Learn page.

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++latest and /std:c++23preview flags.

You can now omit () in some forms of lambdas that previously required them, thanks to P1102R2:

auto lambda = [] constexpr { }; //no '()' needed after the capture list
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");
    }
}
]]>
Mon, 07 Jul 2025 21:32:18 +0000 Blog Staff
C++26: Erroneous Behaviour -- Sandor Dargo https://isocpp.org//blog/2025/07/cpp26-erroneous-behaviour-sandor-dargo2 https://isocpp.org//blog/2025/07/cpp26-erroneous-behaviour-sandor-dargo2 logo.pngC++’s undefined behaviour impacts safety. Sandor Dargo explains how and why uninitialised reads will become erroneous behaviour in C++26, rather than being undefined behaviour.

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.

]]>
Thu, 03 Jul 2025 21:30:04 +0000 Blog Staff
Writing Senders -- Lucian Radu Teodorescu https://isocpp.org//blog/2025/07/writing-senders-lucian-radu-teodorescu1 https://isocpp.org//blog/2025/07/writing-senders-lucian-radu-teodorescu1 logo.pngSenders/receivers can be used to introduce concurrency. Lucian Radu Teodorescu describes how to implement senders.

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_concept that is equal to receiver_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(), or set_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 with set_value(int, int), sometimes with set_value(double), sometimes with set_error(std::exception_ptr), sometimes with set_error(std::error_code), and sometimes with set_stopped(). This implies that a receiver must also be able to accept multiple types of completion signals.

]]>
Tue, 01 Jul 2025 21:27:49 +0000 Blog Staff
C++26: constexpr Exceptions -- Sandor Dargo https://isocpp.org//blog/2025/06/cpp26-constexpr-exceptions-sandor-dargo https://isocpp.org//blog/2025/06/cpp26-constexpr-exceptions-sandor-dargo In recent weeks, we’ve explored language features and library features becoming 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.

constexpr exceptions are conceptually similar to constexpr allocations. Just as a constexpr string can’t escape constant evaluation and reach runtime, constexpr exceptions also have to remain within compile-time code.

Previously, using throw in a constexpr context 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.

 

]]>
Fri, 27 Jun 2025 21:08:51 +0000 Blog Staff
An option(al) to surprise you -- Andreas Fertig https://isocpp.org//blog/2025/06/an-optional-to-surprise-you-andreas-fertig https://isocpp.org//blog/2025/06/an-optional-to-surprise-you-andreas-fertig me.pngIn today's post I share a learning of a customer with you. A while back, a customer asked me to join a debugging session. They had an issue they didn't (fully) understand.

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 function Worker. The function takes a State and a const char* message named data. The function's job is to create a std::optional containing the user data, a C-style string.

 

]]>
Wed, 25 Jun 2025 21:02:59 +0000 Blog Staff
Implementing a Struct of Arrays -- Barry Revzin https://isocpp.org//blog/2025/06/implementing-a-struct-of-arrays-barry-revzin https://isocpp.org//blog/2025/06/implementing-a-struct-of-arrays-barry-revzin Data-oriented design is all about reorganizing data for better performance, and Andrew Kelley’s talk on the topic—especially his use of Zig’s 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 call std::vector<Monster>, and MultiArrayList(Monster) now stores the anims and kinds 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.

]]>
Mon, 23 Jun 2025 20:59:04 +0000 Blog Staff
Reflection voted into C++26: "Whole new language" -- Herb Sutter https://isocpp.org//blog/2025/06/reflection-voted-into-cpp26-whole-new-language-herb-sutter https://isocpp.org//blog/2025/06/reflection-voted-into-cpp26-whole-new-language-herb-sutter The first trip report from the Sofia meeting is available:

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.

]]>
Sun, 22 Jun 2025 05:16:16 +0000 Blog Staff
C++20 Concepts for Nicer Compiler Errors -- Daniel Lemire https://isocpp.org//blog/2025/06/cpp20-concepts-for-nicer-compiler-errors-daniel-lemire https://isocpp.org//blog/2025/06/cpp20-concepts-for-nicer-compiler-errors-daniel-lemire image-33-825x510.jpgTemplates are one of C++’s most powerful features, enabling developers to write generic, reusable code—but they come with a cost: notoriously verbose and opaque error messages. With the introduction of concepts in C++20, we can now impose clear constraints on template parameters and get far more helpful diagnostics when something goes wrong.

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.

]]>
Fri, 20 Jun 2025 00:14:43 +0000 Blog Staff
C++26: More constexpr in the Standard Library -- Sandor Dargo https://isocpp.org//blog/2025/06/cpp26-more-constexpr-in-the-standard-library-sandor-dargo https://isocpp.org//blog/2025/06/cpp26-more-constexpr-in-the-standard-library-sandor-dargo SANDOR_DARGO_ROUND.JPGHere are the standard library features that will soon be usable at compile time. One topic is missing: exceptions. As they need both core language and library changes, I thought they deserved their own post.

C++26: More constexpr in the Standard Library

by Sandor Dargo

From the article:

P2562R1: constexpr stable sorting

This paper proposes making std::stable_sort, std::stable_partition, std::inplace_merge, and their ranges counterparts usable in constant expressions. While many algorithms have become constexpr over the years, this family related to stable sorting had remained exceptions — until now.

The recent introduction of constexpr containers 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, a constexpr std::vector can 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.

]]>
Sat, 14 Jun 2025 00:08:18 +0000 Blog Staff
Fixing exception safety in our task_sequencer -- Raymond Chen https://isocpp.org//blog/2025/06/fixing-exception-safety-in-our-task-sequencer-raymond-chen https://isocpp.org//blog/2025/06/fixing-exception-safety-in-our-task-sequencer-raymond-chen RaymondChen_5in-150x150.jpgSome time ago, we developed a task_sequencer class for running asynchronous operations in sequence. There’s a problem with the implementation of Queue­Task­Async: What happens if an exception occurs?

Fixing Exception Safety in our task_sequencer

by Raymond Chen

From the article:

Let’s look at the various places an exception can occur in Queue­Task­Async.

    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_shared, then no harm is done because we haven’t done anything yet.

If an exception occurs when starting the lambda task, then we are in trouble. We have already linked the current onto m_latest, but we will never call continue_with(), so the chain of tasks stops making progress.

To fix this, we need to delay hooking up the current to the chain of chained_tasks until we are sure that we have a task to chain. 

]]>
Tue, 10 Jun 2025 00:08:25 +0000 Blog Staff
How to Join or Concat Ranges, C++26 -- Bartlomiej Filipek https://isocpp.org//blog/2025/06/how-to-join-or-concat-ranges-cpp26-bartlomiej-filipek https://isocpp.org//blog/2025/06/how-to-join-or-concat-ranges-cpp26-bartlomiej-filipek howtojoinconcat-filipek.pngC++ continues to refine its range library, offering developers more efficient and expressive ways to manipulate collections. In this post, we'll dive into three powerful range adaptors—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_view allows you to concatenate multiple independent ranges into a single sequence. Unlike join_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.
]]>
Fri, 06 Jun 2025 00:02:04 +0000 Blog Staff
Function overloading is more flexible than template function specialization -- Raymond Chen https://isocpp.org//blog/2025/05/function-overloading-is-more-flexible-than-template-function-specialization https://isocpp.org//blog/2025/05/function-overloading-is-more-flexible-than-template-function-specialization RaymondChen_5in-150x150.jpgWhen trying to specialize a templated function for specific types, it’s easy to fall into subtle traps around how parameter types are matched. A colleague recently ran into this issue while attempting to specialize a function for a 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 template

What 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.

]]>
Fri, 30 May 2025 00:01:52 +0000 Blog Staff
C++26: More constexpr in the Core Language -- Sandor Dargo https://isocpp.org//blog/2025/05/cpp26-more-constexpr-in-the-core-language-sandor-dargo https://isocpp.org//blog/2025/05/cpp26-more-constexpr-in-the-core-language-sandor-dargo SANDOR_DARGO_ROUND.JPGIn this article, we review how constexpr evolves in the C++26 core language. We are getting constexpr cast from void*, placement new, structured bindings and even exceptions (not discussed today). 

C++26: More constexpr in the Core Language

by Sandor Dargo

From the article:

Since constexpr was added to the language in C++11, its scope has been gradually expanded. In the beginning, we couldn’t even use if, else or loops, which were changed in C++14. C++17 added support for constexpr lambdas. C++20 added the ability to use allocation and use std::vector and std::string in constant expressions. In this article, let’s see how constexpr evolves with C++26. To be more punctual, let’s see what language features become more constexpr-friendly. We’ll discuss library changes in a separate article, as well as constexpr exceptions, which need both language and library changes.

P2738R1: constexpr cast from void*

Thanks to the acceptance of P2738R1, starting from C++26, one can cast from void* to a pointer of type T in constant expressions, if the type of the object at that adress is exactly the type of T.

Note that conversions to interconvertible - including pointers to base classes - or not related types are not permitted.

The motivation behind this change is to make several standard library functions or types work at compile time. To name a few examples: std::format, std::function, std::function_ref, std::any. The reason why this change will allow many more for more constexpr in the standard library is that storing void* is a commonly used compilation firewall technique to reduce template instantiations and the number of symbols in compiled binaries.

]]>
Wed, 28 May 2025 00:01:22 +0000 Blog Staff
Streamlined Iteration: Exploring Keys and Values in C++20 -- Daniel Lemire https://isocpp.org//blog/2025/05/streamlined-iteration-exploring-keys-and-values-in-cpp20-daniel-lemire https://isocpp.org//blog/2025/05/streamlined-iteration-exploring-keys-and-values-in-cpp20-daniel-lemire image-27-825x510.jpgModern C++ offers a variety of ways to work with key-value data structures like std::map and std::unordered_map, from traditional loops to sleek functional-style expressions using C++20 ranges. By exploring both styles and benchmarking them across platforms, we can better understand how newer language features affect readability, expressiveness, and performance.

Streamlined Iteration: Exploring Keys and Values in C++20

by Daniel Lemire

From the article:

In software, we often use key-value data structures, where each key is unique and maps to a specific value. Common examples include dictionaries in Python, hash maps in Java, and objects in JavaScript. If you combine arrays with key-value data structures, you can represent most data.

In C++, we have two standard key-value data structures: the std::map and the std::unordered_map. Typically, the std::map is implemented as a tree (e.g., a red-black tree) with sorted keys, providing logarithmic time complexity O(log n) for lookups, insertions, and deletions, and maintaining keys in sorted order. The std::unordered_map is typically implemented as a hash table with unsorted keys, offering average-case constant time complexity O(1) for lookups, insertions, and deletions. In the std::unordered_map, the hash table uses a hashing function to map keys to indices in an array of buckets. Each bucket is essentially a container that can hold multiple key-value pairs, typically implemented as a linked list. When a key is hashed, the hash function computes an index corresponding to a bucket. If multiple keys hash to the same bucket (a collision), they are stored in that bucket’s linked list.

Quite often, we only need to look at the keys, or look at the values. The C++20 standard makes this convenient through the introduction of ranges (std::ranges::views::keys and std::ranges::views::values). Let us consider two functions using the ‘modern’ functional style. The first function sums the values and the next function counts how many keys (assuming that they are strings) start with a given prefix.

]]>
Fri, 23 May 2025 23:50:58 +0000 Blog Staff
Owning and non-owning C++ Ranges -- Hannes Hauswedell https://isocpp.org//blog/2025/05/owning-and-non-owning-cpp-ranges-hannes-hauswedell https://isocpp.org//blog/2025/05/owning-and-non-owning-cpp-ranges-hannes-hauswedell This is the first article in a series discussing some of the underlying properties of C++ ranges and in particular range adaptors. At the same time, I introduce the design of an experimental library which aims to solve some of the problems discussed here.

Owning and non-owning C++ Ranges

by Hannes Hauswedell

From the article:

We will begin by having a look at ranges from the standard library prior to C++20, since this is what people are most used to. Note that although the ranges themselves are from C++17, I will use some terminology/concepts/algorithms introduced later to explain how they relate to each other. Remember that to count as a range in C++, a type needs to have just begin() and end(). Everything else is bonus.

[…]

Containers are the ranges everybody already used before Ranges were a thing. They own their elements, i.e. the storage of the elements is managed by the container and the elements disappear when the container does. Containers are multi-pass ranges, i.e. you can iterate over them multiple times and will always observe the same elements.

[…]

If containers are owning ranges, what are non-owning ranges? C++17 introduced a first example: std::string_view, a range that consists just of a begin and end pointer into another range’s elements.

[…]

However, the most important (and controversial) change came by way of P2415, which allowed views to become owning ranges. It was also applied to C++20 as a defect report, although it was quite a significant design change. This is a useful feature, however, it resulted in the std::ranges::view concept being changed to where it no longer means “non-owning range”.

[…]

 

 

]]>
Thu, 22 May 2025 16:40:55 +0000 Hannes Hauswedell
How to break or continue from a lambda loop? -- Vittorio Romeo https://isocpp.org//blog/2025/05/how-to-break-or-continue-from-a-lambda-loop-vittorio-romeo https://isocpp.org//blog/2025/05/how-to-break-or-continue-from-a-lambda-loop-vittorio-romeo Is it possible to write a simple iteration API that hides implementation details and lets users break and continue?

Here's a new article about a lightweight solution using a `ControlFlow` enumeration!

How to break or continue from a lambda loop?

by Vittorio Romeo

From the article:

Here’s an encapsulation challenge that I frequently run into: how to let users iterate over an internal data structure without leaking implementation details, but still giving them full control over the loop?

Implementing a custom iterator type requires significant boilerplate and/or complexity, depending on the underlying data structure.

Coroutines are simple and elegant, but the codegen is atrocious – definitely unsuitable for hot paths.

 

]]>
Thu, 22 May 2025 13:05:47 +0000 Vittorio Romeo
Raw Loops for Performance? -- Sandor Dargo https://isocpp.org//blog/2025/05/raw-loops-for-performance-sandor-dargo https://isocpp.org//blog/2025/05/raw-loops-for-performance-sandor-dargo SANDOR_DARGO_ROUND.JPGUsing ranges or algorithms has several advantages over raw loops, notably readability. On the other hand, as we’ve just seen, sheer performance is not necessarily among those advantages. Using ranges can be slightly slower than a raw loop version. But that’s not necessarily a problem, it really depends on your use case. Most probably it won’t make a bit difference.

Raw Loops for Performance?

by Sandor Dargo

From the article:

To my greatest satisfaction, I’ve recently joined a new project. I started to read through the codebase before joining and at that stage, whenever I saw a possibility for a minor improvement, I raised a tiny pull request. One of my pet peeves is rooted in Sean Parent’s 2013 talk at GoingNative, Seasoning C++ where he advocated for no raw loops.

When I saw this loop, I started to think about how to replace it:

2025-05-08_16-46-14.png

Please note that the example is simplified and slightly changed so that it compiles on its own.

Let’s focus on foo, the rest is there just to make the example compilable.

It seems that we could use std::transform. But heck, we use C++20 we have ranges at our hands so let’s go with std::ranges::transform!

]]>
Wed, 21 May 2025 23:44:22 +0000 Blog Staff
constexpr Functions: Optimization vs Guarantee -- Andreas Fertig https://isocpp.org//blog/2025/05/constexpr-functions-optimization-vs-guarantee-andreas-fertig https://isocpp.org//blog/2025/05/constexpr-functions-optimization-vs-guarantee-andreas-fertig Depositphotos_193487484_S.jpgConstexpr 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;              ③
}
Listing 1

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.

Last, in ③, I return the value of f to prevent the compiler optimizes this program away. If you use Compiler Explorer to look at the resulting assembly, GCC with -O1 brings this down to:

  main:
          mov     eax, 7
          ret

As you can see, the compiler has evaluated the result of 42 / 6, which, of course, is 7. Aside from the final number, there is also no trace at all of the function Fun.

Now, this is what, in my experience, makes people believe that Fun was evaluated at compile-time thanks to constexpr. Yet this view is incorrect. You are looking at compiler optimization, something different from constexpr functions.

]]>
Mon, 19 May 2025 23:41:11 +0000 Blog Staff
C++26: Erroneous Behaviour -- Sandor Dargo https://isocpp.org//blog/2025/05/cpp26-erroneous-behaviour-sandor-dargo1 https://isocpp.org//blog/2025/05/cpp26-erroneous-behaviour-sandor-dargo1 Depositphotos_287607756_S.jpgC++’s undefined behaviour impacts safety. Sandor Dargo explains how and why uninitialised reads will become erroneous behaviour in C++26, rather than being undefined behaviour.

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.

But what is this new behaviour that on C++ Reference is even listed on the page of undefined behaviour? [CppRef-1] It’s well-defined, yet incorrect behaviour that compilers are recommended to diagnose. Is recommended enough?! Well, with the growing focus on safety, you can rest assured that an implementation that wouldn’t diagnose erroneous behaviour would be soon out of the game.

Some compilers can already identify uninitialized reads – what nowadays falls under undefined behaviour. For example, clang and gcc with -ftrivial-auto-var-init=zero have already offered default initialization of variables with automatic storage duration. This means that the technique to identify these variables is already there. The only thing that makes this approach not practical is that you will not know which variables you failed to initialize.

Instead of default initialization, with erroneous behaviour, an uninitialized object will be initialized to an implementation-specific value. Reading such a value is a conceptual error that is recommended and encouraged to be diagnosed by the compiler. That might happen through warnings, run-time errors, etc.

]]>
Sat, 17 May 2025 23:38:13 +0000 Blog Staff
Writing Senders -- Lucian Radu Teodorescu https://isocpp.org//blog/2025/05/writing-senders-lucian-radu-teodorescu https://isocpp.org//blog/2025/05/writing-senders-lucian-radu-teodorescu 2025-05-08_16-35-43.pngIn the December issue of Overload [Teodorescu24], we provided a gentle introduction to senders/receivers, arguing that it is easy to write programs with senders/receivers. Then, in the February issue [Teodorescu25a], we had an article that walked the reader through some examples showing how senders/receivers can be used to introduce concurrency in an application. Both of these articles focused on the end users of senders/receivers. This article focuses on the implementer’s side: what does it take to implement senders?

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_concept that is equal to receiver_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(), or set_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 with set_value(int, int), sometimes with set_value(double), sometimes with set_error(std::exception_ptr), sometimes with set_error(std::error_code), and sometimes with set_stopped(). This implies that a receiver must also be able to accept multiple types of completion signals.

The need for completion signatures is not directly visible in the receiver concept. There is another concept that the P2300 proposal defines, which includes the completion signatures for a receiver: receiver_of<Completions>. A type models this concept if it also models the receiver concept and provides functions to handle the completions indicated by Completions. More details on how these completions look will be covered in the example sections.

]]>
Thu, 15 May 2025 23:33:55 +0000 Blog Staff