This year marks the tenth anniversary of Meeting C++ in Berlin.

Once again my colleague and I made the decision to travel by train to the venue. The trip was very comfortable and we experienced no meaningful delays. In total, the trip took ~13 hours. I would recommend this mode of travel over flying not just for the sake of the climate (which was a very big motivating factor) but also because I just didn’t feel tired and sore the same way I feel when I fly.

Thursday (day 1)

Keynote - Fear in Tech

In his keynote, Titus Winters puts focus on the fear experienced by developers. One of the main take-aways from this is the idea of creating an environment that fosters psychological safety. To achieve this it is important to focus on people more than technical excellence.

In his opinion, psychological safety is fundamental to any team’s success

It is more important to be a good person than to be a good programer – Titus Winters

Winters also identified three types of environemnt:

  1. Power based: the idea that there is a chain of command to follow; removing autonomy
  2. Process based: every action is outcome is controlled by process; restricting creativity
  3. Outcome based: teams works towards a common goal

It was found that outcome based environments are generally the most successul, even with power dynamics and process in place; these can be ignored and changed in order to meet the goals.

According to DORA culture is 30%+ of success.

Winters stressed that the following points are key for success in outcome based environments:

  1. Documentation that aids a developer in their daily work
    • Getting started
    • Contributing changes
  2. Discussing values
    • Team agreements
    • Boy scout rule
  3. Giving kudos
    • Do it publicy
    • If the kudos is for someone outside of the team, reach out to their manager to give kudos
  4. Owning mistakes
    • We’re human; they happen
    • Encourage the sharing of mistakes so every can benefit from them

On the topic reviewing code, Winters recommends the following set of questions:

  • How will this work over time?
  • How will this work for different peopl/teams/dynamics?
  • What is this good for?
  • What is this not good for?

I particularly like Winters’ take on tech interviews claiming they should focus on code review. The interviewers should provide the code and ask the candidate to review it. This proovides a meaningful interaction that not only demonstrates a candidates technical competence but, more importantly, gives the interviewer a chance to assess how the candidate interacts in potentially delicate social interactions.

C++ Modules

This is an intro to modules focussing particularly on *named” modules and ignoring parts of modules that do not, yet, enjoy wide implementation support.

Module names are not required to map to physical file structure. Though I would model my physical file structure after modules as I like the extra structuring.

Header units were skipped since they are not widely available.

PSA for file sets in CMake 3.23 which are important for modules in 3.28+.

Include directives are still part of most projects until Header Units become generally available. To do use we use the Global Module Fragmet:

module;

#include <vector>

export module A;

...

Andreas Weiss also demonstrated how to go about wrapping a “legacy” library in a module unit. Personally, I think this is a lot of work and would just conisder using the GMF and documenting what might to be explicitly. Daniela Engert modularized SDL and is a good source for seeing what it would take if you are interested.

Templates made easy

Interview questions (again!)

  • What’s something you know that you could teach a junior?
  • What’s something you don’t know, or would like to know more about?

A nice piece of advice for creating concepts is to group conceptual requirements with boolean logic and to put requires code inside a requires block. This avoids accidentlly omitting the requires keyboard inside a requires block.

Many great examples of applying concepts and contraints. Anyone willing to no more should really watch this video when it’s released.

Portable floating point calculations

Lots of background on lack of real compliance with IEEE-754 floating point. Guy mentioned the Goldberg paper as a good foundational reading to gain a better understanding of floating point representation and arithmetic. It’s a very interesting read.

What Every Computer Scientist Should Know About Floating-Point Arithmetic

Unfortunately there was no real solution on offer, though Guy has proposed the following papers to introduce reproducibility in C++:

  • P3375 - Reproducible floating point
  • P2746 - Deprecate and Rplace Fenv Rounding Modes

There is no Silver Bullet

Iglberger takes us through an implementation using GoF patterns and transforms it with std::variant to remove all traces of polymorphism. After showing the impressive performance gains we could see, he proceeds to pull the rug out from under our feet by demonstrating that the architecture is now fully coupled.

Finally, he transforms the original example using type erasure.

This is what makes us developers; knowing these things and choosing the right solution. – Klaus Iglberger

The Famous MeetingC++ Quiz

The day rounded off with a social gathering before Diego took the stage to bend our minds with his fantastic quiz. My team scored 63 points out of 100 possible (had I not been outvoted we would have instead had an 73… Then again, if I had been paying attention in the first quiz I wouldn’t have cost my team 8 points XD).

Friday (day 2)

Centre Keynote

Hanna Dusíková talks us through the contexpr parser of clang. After walking us through how clang sees our code in constexpr she walked us through the various containers and highlighted constexpr compatibility. Once it became apparent that most containers shoul be constexpr she challenged the room to write the papers since that is the only reason why we don’t have more constexpr containers in the standard. This was cemented when the list of constexpr abilities were listed; there is very little that cannot be constexpr since C++20.

All of this culminated in the unveiling of HAMT (Hash Array Mapped Trie) which Dusíková would like to see introduced to the standard once all of the constexpr gaps are filled:

  • P3068 - allowing exception throwing in constant evaluation
  • P3378 - constexpr exception types
  • P3309 - constexpr atomic and atomic_ref
  • P3037 - constexpr std::shared_ptr
  • P3125 - constepxr pointer tagging
  • P3074 - trivial unions
  • P3372 - constexpr containers and adapters
  • P3295 - freestanding constex rcontainers and constexpr exception types
  • P3367 - constexpr coroutines
  • P3391 - constexpr std::format
  • P3449 - constexpr std::generator
  • D1974 - non-transient constexpr allocations using propconst

Perhaps the coolest part of all of this (IMO) is that we could create, start, and suspend a coroutine in a constexpr context (i.e. at compile time) and then resume the coroutine during runtime!

Someone asked about debugging compile time code. Dusíková suggested you could attach to the compiler, but don’t. There are no good tools yet, but Dusíková has created her own __builtin that allows her to print to the compiler diagnostic output during compile time…

Pipeline Architecture with operator|

Boguslaw Cyganek demonstrated how to overload operator| to allow for a more ranges like syntax to support function composition. He referred to Function Programming in C++ by Ivan Čukić which is a fantastic piece of literature if you are interested in the function programming domain.

The main point Cyganek wanted to get to was to demonstrate how std::expected can lift the pipeline architecture to the next level through its ability to communicate success or failure. Unfortunately, it came undone when the different error types at different parts of the pipeline were merged in to a std::variant since this now couples the entire pipeline in a way that could be awkward to extend.

Perhaps I will investigate this issue further myself and see what solution I can devise.

C++ Concepts

Use static_assert to test concepts.

Using requires Concept<decltype(arg)> is problematic if arg is a reference which means we also need to use utilities like std::remove_reference_t or std::remove_cvref_t which we can embed in the concept itself.

Instead of creating a concept for everything, consider preferring:

if constexpr (requires { coll.push_back(val); }_{
    coll.push_back(val);
else coll.insert(val);

which keeps the implementation details hidden where a concept would expose them.

Josuttis also demonstrated how to use subsumption to build a hierarchy of concepts where each new level builds on the previous.

This was a very good introduction to concepts and I would recommend watching this video when it is released.

Software Engineering Completeness

Peter Muldoon presented his take on project management and what “done” really means. This talk is only half of the material that he has presented before. We wait with baited breath for the next installment.

In this part we heard nothing that is particularly new for a seasoned developer but it is nonetheless worth repeating as he frames it in a bastardization of Maslov’s hierarchy of need where the bottom is comprised of developers performing the minimum required to survive product development and the seond tier in which engineers are able to leverage verification and efficient planning to continually maintain a product.

In his second part he teases the final tiers in his pyramid where he turns the tables on the customer instead, encouraging developers to pose piercing questions to the customer in order to glean more insights and better estimate the work required.

Guide to C++ Object Lifetime

This was a whirlwind tour of object lifetime in C++. Mostly Müller focussed on pointers and provenance as this is a tricky part of the language. That, and temporary lifetime extensions which got fixed in C++20 so that temporaries in a range-for have their lifetimes extended correctly.

On the subject of placement-new Müller advised using std::start_lifetime_as on the pointer to ensure that the object is correctly constructed in place with its lifetime started.

Müller has given this presentation at conferences before and has graciously provided the material on his website already.

C++’s Next Decade

Herb Sutter took to the stage in typical enthusiastic fashion and wooed the crowd by opening his keynote in German (he translated to let everyone else in on the joke).

Sutter wants to achieve two things in the immediate future:

  1. focus on type and memory safety to achive parity with other languages
  2. Reflection and code generation

Safety in Context

type bounds init life safe which are teh four most severe CWE categories that memory safe languages do better.

Reading unit local vars is no longer UB; it’s erroneous as of C++26. This automatically eliminates a class of bugs and does so with no action required from developers; just recompile in C++26 mode. If you are not able to run in C++26 mode yet, then GCC and Clang have a flag to set the bit pattern of uninitialised variables such that these bugs can be more readily detected by sanitizers:

  • -ftrivial-auto-var-init=pattern

In C++26 if, for some reason, really want an indeterminate value, then there is an attribuate for that: int a [[indeterminate]];

We also got a friendly reminder that we have an entire subset of the language that is a UB-free playground, namely constexpr. With more and more things becoming possible in constexpr (just see the list from Dusíková’s keynote) it won’t be long before UB is removed from the language altogether.

Attention was then turned to reflection and code generation.

Reflection is primarily static unless you opt to store it and use it runtime. This is unlike how other languages perform reflection, but it should remove any security concerns that could arise from runtime reflection.

P2996 opens the doors for Herb’s P0707 (meta classes) which will make it easy to generate correct code by default such as generating an interface based on a class definition:

class (interface) Widget {
    void f();
    int number();
};

which generates:

class Widget {
public:
    Widget() = default;
    virtual ~Widget() = default;
    Widget(Widget const&) = delete;
    Widget& operator=(Widget const&) = delete;

    virtual void f() = 0;
    virtual int number() = 0;
};

so that devs never have to remember how to correctly define the special members in an interface.

Sutter’s enthusiasm is infectious and it felt like most people in the room wanted all the things mentioned to succeed.

Saturday (day 3)

Clean Code! Horrible Performance?

Derek Jones Aura of Software Quality posits that quality is meaningless marketing jargon.

It is generally agreed that clean code improves reliabilit, security, and maintainability

Dargo claims that clean code is not the most efficient or the fastest code, but it is optimised for maintainibility, reliability, and security and challenges that the fastest code is not always the best goal

Engineering is in he crossroads of defineing and recognising what is good enough.

An interesting talk, but it lacked any connection to the real world. This felt purely hypothetical and ultimately a bit of a let down. I was rather hoping to see some empirical data and understand the argument for choosing the clean code which is assumed to be slower.

Fast and Small C++

Fertig showed how EBO works and how [[no_unique_address]] can be used to implement something like a compressed pair which is how std::unique_ptr can store a pointer and stateless deleter without being larger in size than the size of a pointer. We can achieve this custom deleters in C++20 by using cpature-less lambdas:

tempalte <class T, class Deleter>
using unique_ptr_deleter = std::unique_ptr<T, decltype([](T* t){Deleter(t);}>;

for C++23 remove the implicit this pointer to reduce the number of instructions caused by indirection.

tempalte <class T, class Deleter>
using unique_ptr_deleter = std::unique_ptr<T, decltype([](T* t) static {Deleter(t);}>;

Look at fbstring for SSO techniques

Contracts

Timur Doumler offered a detailed overview of what is coming in P2900.

Closing keynote

This closing keynote by Peter Sommerlad was a wondering of why the developers of today develop code seemingly ignorant to the learnings of the past. Indeed, when queried, not everyone raised their hands when asked about writing tests. After the keynote some developers even asked about the complexity they perceived when writing tests; an argument that simply does not hold when functions and classes are kept small and simple!

Sommerlad gave plenty of reading material that should be worth reading as a history lesson, if nothing else:

As if to cememt all the teachings of the past, Sommerlad walked us through the principles of good software.

Some other key takeaways inlude:

  • Simplicity is the most overlooked principle
  • Architetts should also implement
  • Abstraction is giving a name to “stuff”. We hide details behind the name i.e. encapsulation
  • Less code == more software

Do the simplest thing that could possibly work – Ward Cunningham

Lean on the type system to have the compiler give an error for design flaws in your types. Strong typing is a powerful idiom to aid with this, especially in the face of C++’s implicit conversions between types.

All in all, I feel like there was a good message here: understand how we got where we are today by studying the literature of the past. A sentiment I wholeheartedly agree with.

Sommerlad’s presentation material can be found here.

That’s all for this year

With that, the conference is over. I am taking the train back to Sweden in the morning. Meeting C++ is a really well organized conference that I have attended most years since I first visited in 2018. I intend to return next year again.