Meeting C++ 2025 Trip Report
27 Nov 2025This November, I had the opportunity to attend the famous Meeting C++ conference. Located in Germany, it attracts many C++ developers not only from continental Europe, but also from the UK and the USA. I am grateful to the organisers, especially Jens Weller, for accepting my proposal to be part of such a great lineup of talks across five tracks during three days. So yes, it was huge.
Let me share my thoughts about a few talks and what I’ve found especially interesting.
Software and Safety keynote
Anthony Williams worked on the C++ concurrency standard, wrote a lot of articles and a book “C++ Concurrency in Action”, which is an excellent crash course into (non-)crashing multi-threaded programs. Now he explores the automotive industry, which has a special interest in concurrency and safety from undefined behaviour in C++.
I like the “Swiss Cheese” concept Anthony carried throughout his keynote talk, “Software and Safety”. It likens the system to a stack of Swiss cheese layers with randomly placed and sized holes in each slice, mitigating the overall risk. There is no silver bullet. You can only decrease the failure risk by having multiple techniques in place, like:
- Design your system to minimise the potential for problems
- Use static analysis
- Test with potentially problematic input
- Fuzz test
- Use sanitisers and hardened libraries
- Use contracts
It was a perfect start to the conference, providing the tone of safety for critical systems in C++. I’ve seen and spoken with many attendees working in highly regulated environments, such as automotive, aerospace, and healthcare. All of us would prefer these safety-critical systems to be written with these ideas in mind. For regulated financial institutions, it’s not that critical, but it’s also a key factor in ensuring a safe and secure language and foundational libraries.
From Acrobatics to Ergonomics - A Field Report on How to Make Libraries Helpful
Then I moved to an excellent and entertaining talk by Joel Falcou from INRIA on designing software libraries for scientists to use. It’s a different approach compared to writing libraries for hardcore C++ developers. You cannot just throw kilobytes of template errors at users without a reasonable explanation of the errors and, more importantly, actions to fix them from a user perspective. Joel explained how concepts, type systems, and proper API design can greatly simplify the developer experience. Joel believes that library developers should care more about users, and modern C++ makes it easier.
In Rust, developers have excellent diagnostics support from the compiler, and rich support for custom diagnostics is also provided to libraries via the form of annotate-snippets-rs crate and at the attribute-level with #[diagnostic::on_unimplemented] (docs). C++ compilers are becoming increasingly capable of reducing error clutter, but there is still a long way to go.
Also, a simple and intuitive design doesn’t have to be non-extensible. The speaker explained that intuitive means the incorrect usage is flagged clearly, and all components adhere to the Single Responsibility SOLID principles. Extensibility means that users should be able to combine pieces of the API and obtain sensible results. Power users should be able to customise their API usage to their own corner cases, and finally, developers should have a clear path to extend the API.
Lessons learned from the talk.
- Use Concepts and static asserts to enforce API design
- Use
if constexprand static asserts to simplify metaprogramming - Prevent problems earlier with proper diagnostics
Harnessing constexpr: A Path to Safer C++
Mikhail Svetkin spoke about memory safety. Undefined behaviour can be easily stopped by LLVM sanitisers, but it’s not the only way. Developers could start sprinkling constexpr into functions, allowing them to operate not only at runtime but also at compile-time. The main side effect of constexpr is the lack of undefined behaviour. So if your constexpr unit tests work on code, it’s free of undefined behaviour. It allows unit tests for such functions to run even before they are executed! Maxing this out requires some tricky techniques that Mikhail has shown, and the result is fascinating — unit test errors are displayed in your IDE before compilation.
The constexpr support has grown extensively during the last standards. I cannot resist mentioning this evolution list:
-
C++11: expression
-
C++14: variables, control flow, array
-
C++17: lambdas, string view, if constexpr
-
C++20: string, vector, virtual functions, try, new/delete
-
C++23: basic math, unique_ptr, optional, variant
-
C++26: sorting, floating-point math, atomic, hashes, exceptions
-
C++29: format
Monadic Operations in C++23
Robert Schimkowitsch delivered a great, well-structured and perfectly paced talk that brought functional concepts to engineers who used to develop in an imperative style.
The outcomes of this talk are to understand what functors and monads actually do, how to use monadic operations from the standard library and how to build a functional-style program based on this foundation.
It is a useful talk for whoever is not so familiar with monadic concepts. Users of Haskell and more practically oriented languages with functional concepts, like Rust or Swift, could also benefit from this knowledge to find the subtle differences in behaviour.
Asking Stoopid questions
The keynote, as it should be. Frances Buontempo, a seasoned math teacher and educator, explained how to teach people, how to learn, and how to tackle the learning process on one’s own. A philosophical keynote, with food for thought and references to my favourite cyberpunk writers, Neal Stephenson and William Gibson.
int != safe && int != ℤ
An insightful talk from Peter Sommerlad about another safety facet of C++ — undefined behaviour with integer overflow. Regulated environments like MISRA require careful handling of overflows and the resulting undefined behaviour.
Built-in types are limited in size (they are not math integers), we can do different things for, say, addition:
-
Wrap them (
-1after0xFFFFFFFFF) -
Saturate (
0xFFFFFFFFF+ 1 stays0xFFFFFFFFU) -
Panic or throw
It’s an inherent property of machine types. Safety-aware languages like Rust have a variety of operations on the same integer type:
let mut x: u32 = 100;
assert!(x+1 == 101);
assert!(x.checked_add(1) == Some(101));
assert!(x.strict_add(1) == 101); // panics on overflow
assert!(x.overflowing_add(1) == (101, false));
assert!(x.saturating_add(1) == 101);
x = 0xFFFFFFFF;
// assert!(x+1 == 0); // panics in Debug mode, overflows in Release
assert!(x.checked_add(1) == None);
// assert!(x.strict_add(1) == 0); // panics on overflow
assert!(x.overflowing_add(1) == (0, true));
assert!(x.saturating_add(1) == 0xFFFFFFFF);
To be fair, it’s not MISRA-compatible, since it provides a set of specific requirements, such as not mixing signed and unsigned types, restricting type promotions and limiting operations for signed/unsigned types
The idea Peter proposed is to use special wrapper types that simulate the ℤ algebraic group (signed integers) with arbitrary precision and the mentioned operation semantics without overflows. His set of libraries are header-only C++20, providing the following types:
#include <pssodin.h>
constexpr pssodin::cui32 x{10}, y{20}, z{x+y};
static_assert(z == pssodin::from_int(30));
It also works with primitive types:
int32_t x{10}, y{20}, z{0};
assert(!pssodin::add_overflow(x, y, &z) && z == 30);
A distinctive feature of this library is compile-time checks for type eligibility for the majority of operations. Hence, the library is almost entirely constexpr, greatly simplifying testing for undefined behaviour. The API design is based on lean enum classes, which are more performant than a class with an integer data member.
What about having some of these features in a C++ standard? Not so good as with external libraries and other languages. With C++26, some saturation helpers are available in the std library, but not overflow:
static_assert(std::add_sat(10, 20) == 30);
C++20 also improved the situation a bit with tiny helpers std::cmp_equal to avoid common pitfalls with signed/unsigned comparison:
static_assert(-1 > 1U);
static_assert(std::cmp_less(-1, 1U));
static_assert(-1 == 0xFFFFFFFFU);
static_assert(std::cmp_not_equal(-1, 0xFFFFFFFFU));
So, for developers dealing with integer arithmetic, MISRA requirements, and older standards, Peter’s library is a godsend. Impressive work.
The Missing Step: Making Data Oriented Design One Million Times Faster
A keynote-style talk from Andrew Drakeford. He explained how a methodological and systematic approach allows for solving complex problems in financial applications. He outlined ideas from George Polya’s book “How to Solve it”] (goes to my reading list).
It’s much better to listen to this talk and experience a problem-solving journey with the speaker.
Still, I’d like to mention key takeaways (credits to the author):
- Design addresses a highly dimensional problem.
- Logical algorithm design
- Physical optimising spatio-temporal memory use patterns
- Idiosyncratic aspects of the actual problem itself.
- Working through the problem space in a structured way
- Always look to expand the context of your thinking around problem areas
- Draw pictures and solve easier ancillary problem
Unlocking the Value of C++20 Features
A day wrapped with a good overview by Alex Dathskovsky from ScyllaDB of the new C++20 and C++23 features, spanning two talks. It’s handy to have an overview and a reminder to evaluate some new C++ features, given the vast scope of the recent standard. There are a few things I’ve found especially useful and interesting.
Generic lambdas and simplified metaprogramming:
auto gen_lambda = []<typename T>(T a, T b, auto c) {
return a + b + c;
};
Constexpr’s are everywhere, even in virtual hierarchy — what a blasphemy:
struct Animal {
constexpr ~Animal() noexcept {};
constexpr virtual std::string say() const = 0;
};
struct Cat : Animal {
constexpr virtual std::string say() const override { return "Meow"; }
};
int main() {
static constexpr const Cat cat;
constexpr const Animal& animal = cat;
std::cout << animal.say();
}
Transparent comparison for containers. It’s a tricky technique that unlocks more performance while working with standard containers:
std::set<std::string, std::less<>> foo;
Since C++20, it is allowed to specify a transparent hasher for hashing containers, skipping key copy:
struct transparent_hash {
{
using is_transparent = void; // a key ingredient
size_t operator()(const char* s) {
return std::hash<std::string_view>(s);
}
size_t operator()(std::string_view s) {
return std::hash<std::string_view>(s);
}
};
std::unordered_set<std::string, transparent_hash, std::equal_to<>> foo;
// no intermediate std::string constructed
foo.find("a C string");
foo.find(std::string_view{"a string view"});
Speed for free - current state of auto-vectorizing compilers
Who doesn’t want speed for free? Stefan Fuhrmann agrees and explains how the automatic vectorisation works in modern compilers. Of course, developers can call compiler intrinsics or provide compiler hints to insert SIMD instructions here and there. It turns out tha modern clang with -O2 and gcc with -O3 optimisation levels can vectorise simple scalar loops. They are still unable to produce masked instructions to care about data which doesn’t fill the whole SIMD lane. So your typical loop over data should be split into two: a main loop for evenly sized chunks and a tail loop. Compiler engineers do a fantastic job of optimisation. Figuring out whether you can rely on them and bring it to the audience — it’s a great job too!
Why managing C++ dependencies is hard (and what to do about it)
Kerstin Keller presented the journey of one software company from a bunch of prebuilt libraries committed to VCS to a modern Conan 2.0-based build system, with a special emphasis on Windows. It’s always great to hear about experience with Conan across different areas and for different platforms.
Sanitize for your Sanity: Sanitizers tools for Modern C++
Last but not least — my humble talk.

The slides are here on my website. The recordings would eventually be available, too.
According to the Swiss Cheese concept, it is mandatory to use multiple levels of defence. Type system, linters, undefined behaviour check via constexpr sprinkles — it is only a part of the whole deal. At runtime, you can do much more with sanitizers (address sanitizers, thread, memory and undefined). I explained the best ways to work with them, especially how to tailor them to a complex mix of libraries, instrumented and non-instrumented, which is an extremely common but usually overlooked scenario. Also, I tackled a problem of multi-language integration of Rust and C++ code, when using sanitizers to track cross-language problems. So it’s not a choice between Rust and C++, it is a question of making them work better together. As usual, when I am anxious, I speak very fast, which is definitely a problem when delivering complex topics to the public, so there is room for improvement. Nevertheless, slides are always available online, and I am happy to help and give advice on memory safety and sanitizers usage.
Conclusion
This year was turbulent for the world, the industry, developers, and conference organisers worldwide. Why even attend conferences and read books when LLMs could provide all the knowledge of mankind (and mistakes, too)? Despite this, Meeting C++ was filled with great talks, enthusiastic speakers, and curious attendees. The most appealing to me was a shared sense of C++ moving forward — especially towards greater safety. I also shared my knowledge in the talk, and I hope it will help make C++ a better and safer place.
It was terrific to meet developers from many industries, with expertise across different languages and domains. It is energising and makes you feel more confident about the community, the ecosystem, and the people behind it.
See you all next time!