C++ Annotated December 2021: 2021 C++ Highlights, Thread Safety in C++ and Rust, 2022 Conferences, and More
We have all the December news for you in our latest monthly C++ Annotated digest and its companion, the No Diagnostic Required show.
If you have already subscribed, feel free to skip straight to the news. If this is your first time here, let us quickly take you through all the formats we offer. You can read, listen, or watch our essential digest of last month’s C++ news:
- Read the monthly digest on our blog (use the form on the right to subscribe to the blog).
- Subscribe to C++ Annotated emails by filling out this form.
- Watch the No Diagnostic Required show on YouTube. To make sure you hear about new episodes, follow us on Twitter.
- Listen to our podcast – just search for “No Diagnostic Required” in your favorite podcast player (see the list of supported players).
2021 was a great year for C++ despite the ongoing pandemic. December captured many of the year’s highlights, which we’ll cover in the Learning section. Thanks for staying with us in 2021! Inr 2022 we hope that C++23 will be successfully finalized, C++17 adoption will rise, new standards will emerge, tools will evolve faster, and more offline and hybrid events will appear. Watch the December episode to learn more:
Or, read the digest below.
- Language news:
As usual, here’s our round-up of some of the new or updated proposals being considered by the standards committee.
Last month, we looked at the portable assumptions paper, P1774, which was reinvigorated with a view to making it in for C++23.
This month sees an r5 update with minimal changes – mostly just extra clarifying material added upfront in response to discussion on the mailing lists. The only outstanding concern (not captured in the paper) is about potential implementation difficulties with one compiler. The design itself seems all set to go to the polls, which should be open by the time this is published and will run until the plenary session on February 7, meaning there’s still a good chance it can make it in for C++23!
That said, there is one issue that has been raised, by way of a new paper, P2507r0. The issue is fairly subtle and won’t really matter to most people, most of the time. But, currently, the assumptions paper (P1774) specifies that the category of the expression in an assumption is an assignment expression. That’s not because assignment is a use case we specifically want to support. But in C++ there is a hierarchy of expression categories, with assignment expressions being the second most liberal, near the top of the hierarchy. Conditional expressions are more restricted, but they seem to cover everything we can think of that we would need for specifying assumptions (and even a bit more). So the thinking behind this paper is that we should specify the most conservative type of expression that meets our known use cases, as we can always expand it later, whereas reigning in an overly liberal expression category would be much harder!
On the flip side, all existing platform-specific extensions that provide assumptions capabilities today use assignment expressions! So using those is, arguably, following existing practice. And if someone uses a more creative type of expression, we may lock them out of using the new, standard, portable feature.
The good news, though, is that this issue being raised shouldn’t preclude P1774 getting voted in for now. Then P2507 could still be discussed, and applied against it, after the design freeze – even as late as a national body comment, if necessary – so there’s time!
Another paper we’ve looked at before is P2300, “std::execution” – the spiritual successor to the executors papers. If you’ve been following this, you’ll know this is an important paper, which potentially touches on, or even underpins, several other in-flight proposals (Networking, for example).
This new revision contains 12 entries in its revision history for R3 – some small, but some more impactful. It’s good to see such active advancement on the topic, but it does seem too active, still, to make it for C++23.
There’s also a new paper, P2504r0, that could be seen as supporting material. It doesn’t actually propose anything (other than its own conclusions) but is useful background reading. It also makes some rather bold claims. From the intro, it says that it “aims at providing proof that the senders/receivers model proposed by [P2300r2] can constitute a global solution to concurrency.” By this it means that all concurrency primitives, such as mutexes and semaphores, can be expressed in terms of tasks with constraints – and that these tasks can be scheduled optimally and, therefore, be more performant than using the primitives. It then goes on to show that computations are a superset of tasks that can do more things that are useful (error handling, completion notifications, and heterogeneous composition). Since it equates computations with senders from the senders-receivers model of P2300, it concludes that everything discussed applies to that model.
In the General takeaways section it says:
“We’ve shown in this paper that computations can be used as a general mechanism for solving all concurrency problems. We’ve also shown that computations can be used as a top-down mechanism to describe concurrency; thus it provides a way for doing structured concurrency. All these can be made without compromising safety, and ensuring the maximum efficiency.”
It also states that “the programmer will no longer need to add locks into the code”, concluding that “computations solve concurrency”.
The meat of the paper is couched in somewhat mathematical terms, but nothing too heavy, mostly just set notation and terminology from logical proofs. It’s a good read, and rings true. But, while it chimes with what I have read and experienced in some functional languages, I’m not enough of an expert in the field to be able to say, with authority, that these claims are met. Let’s see where the discussion goes.
A new paper that dropped this month is “std::generator: Synchronous Coroutine Generator for Ranges” (P2502r0). If that title sounds familiar, it’s because we discussed it last January. But didn’t we just say it was a new paper?
The acknowledgements section should clear things up:
“I’d like to thank Lewis Baker and Corentin Jabot, whose P2168 I looted shamelessly for this proposal. This paper is presented as a new revision of their unpublished D2168R4 for continuity of design.”
So we could consider this a fork of P2168 – closer to an r5, perhaps.
Since we’ve covered it before, just a quick recap: C++20 coroutines are a language feature without the necessary library support. A fully featured reference library exists in cppcoro, from Lewis Baker, and the expectation was that we’d get much of that added for C++23. That’s been happening, but at a slower pace than expected (presumably due to the pandemic). This proposal introduces support for the most fundamental type of coroutine – the generator. A generator is a way of continuously yielding values to the caller. In a way, it is one of the simplest (useful) coroutines. But the fact that this paper runs for 28 pages (up from 23 in P2168) suggests that making that work correctly is not as simple as it sounds. A particular complication is support for recursive coroutines – a coroutine that yields a generator of the same type. The paper gives examples of why this is useful, and why it’s hard to support – and support efficiently.
I’m hoping this is in time for C++23, but it’s cutting it close!
Monadic operators for std::expected
Here’s another new paper that might sound familiar. That’s because I’ve been talking about this one for a few years now! Ever since the monadic operations for std::optional were first proposed (and recently adopted into C++23), it was only a matter of time – and someone writing the paper – that the same operations be proposed for
std::expected. Now that
std::expected is in its final stages of wording review, it seems like a good time to kick that off.
Again, we’ve covered it more than once before, but to recap: these operations let you sequence operations (functions or lambdas) that return values wrapped in
std::expected as if they returned the expected value, and shuffles the error handling off to a dedicated step, usually at the end. This is closer to the exceptions model, with the control flow pushed into the infrastructure, albeit with a bit more syntax. But along with that syntax you also get determinism and more flexibility in how you want to handle things. And in cases where the error path is common enough, this approach should perform better, too (at least until we get something like P0709).
C++ at the end of 2021
On the very last day of 2021, Bartlomiej Filipek posted the final report about the state of C++ and its ecosystem in the past year. Among the many things mentioned there, it’s worth highlighting the final picture of the C++ standard conformance in the major compilers. 2021 saw three standards being worked on in parallel: C++17 was finalized in all three major compilers, work on C++20 is in progress, and C++23 is already in active development in terms of compiler implementation.
Regarding the standards, you can learn about the major things that are coming or at least highly possible in C++23 from the article. While the overall changes happening to the language are mostly welcomed by the community, Nicolai Josuttis commented on the report to highlight a problem mentioned by some members: the lack of bug fixes in the language, and raw features being added without the possibility to fix them because of backward compatibility.
2021 also became a year of tooling in the C++ ecosystem, with many significant updates to popular tools such as IDEs, compilers, and code analyzers, as well as continuous work on the implementation of modules and the growing popularity of Clang-based tools. Compiler Explorer had a great update in 2021, too, adding support for compiling multiple files with CMake.
The report also lists the notable C++ books that were published, the online and hybrid events that happened, and the various community surveys that were held in 2021. The author also presents the results of the survey he ran among his blog audience earlier in December. Check it out to learn about the latest C++ trends such as how quickly the standards are being adopted and what tools C++ developers prefer.
C and C++ development on Windows: encoding issues
An interesting article was published at the end of 2021 dedicated to encoding issues on Windows and in standard C and C++ libraries. It first discussed the fact that Windows internally uses UTF-16 and a so-called narrow API that has limited access to the system. As a consequence, the standard library (and your portable software on Windows) cannot handle anything but ASCII. There is a way to force a process to use UTF-8 as the process code page on Windows now, but the approach still suffers from issues with UTF-8 input and output.
Another issue with cross-platform C/C++ development is that Windows distinguishes between text and binary streams, but macOS and Linux do not. However, the standard also specifies that standard input, output, and error are all open as text streams, and there’s no portable method to change the stream mode to binary. This leads to performance degradation when reading and writing standard streams.
As a bonus, the article introduces the libwinsane library, which can help address these problems.
Thread safety in C++ and Rust
This article by Josh Haberman compares the thread-safety approaches in C++ and Rust. It maps C++’s thread-safe and thread-compatible terms to Rust’s Sync and Send traits. The major difference lies in the thread-safe approaches taken. Rust models this within the type system, and so it gets checked by the compiler. It might look a bit unusual that Rust forbids shared mutable access at the language level, but allows interior mutability where mutations are allowed on an immutable reference. But when a different view on the terminology is taken, it starts looking more logical. Would you prefer adopting Rust’s approach, or do you feel C++ terms are less confusing and more comfortable to use?
The evolution of lambdas in C++14, C++17, and C++20
We love Jonathan Boccara’s overview posts, which always help sort out our understanding of whatever topic he writes about. This one about C++ lambdas is no exception.
The article goes over the key milestones in how C++’s lambdas have evolved through the recent language standards. It starts with C++14, which introduced default and template parameters to lambdas, added the ability to use generalized capture, and made it possible to return a lambda from a function. With that, C++ lambdas became very similar to regular functions and thus very usable in everyday coding.
With C++17, lambdas became available in contexts evaluated at compile time because they could now be declared
constexpr. Later, with the advent of C++20, that enabled many STL algorithms in the
constexpr mode, as you could easily manipulate collections at compile time. The second big enhancement from C++17 in lambdas was the ability to capture a copy of
*this. It seems minor at first glance, but it helps avoid Undefined Behavior and thus unwanted crashes that might happen when the object is already destroyed while a lambda is still capturing a pointer to it.
Finally, C++20 improved lambdas to make them look more like regular functions, now with the classic syntax to define templates and to capture a variadic pack of parameters.
The evolution of functions in modern C++
We’ve talked about lambdas, but what about functions in modern C++? Marius Bancila has overviewed the evolution of this major development element. It doesn’t go deep into each function type or function-related features, but works as an overview and a convenient index of each function addition appearing in C++11, C++14, and C++20.
The post begins by listing the very basic functions that C++ developers had before C++11.
C++11 made functions more expressive with things like function templates with a variable number of arguments, an alternative syntax for the return type and
decltype, more special member functions, and default and deleted specifiers. At the same time,
constexpr functions that are evaluated at compile time shifted the focus from programming at runtime to programming at compile time.
C++14 generalized functions. A return type was no longer required as compilers were taught to deduce the return type from the return expression(s) present in the function body.
Finally, C++20 advanced the earlier function-related features with immediate functions that must be evaluated at compile time, as well as (un)constrained abbreviated function templates whose function parameters could be defined with the
The post also touches on coroutines and lambdas, but really briefly.
How do you think lambdas and functions might evolve further in standards like C++23 and C++26? Please share your perspective in the comments!
C++ conferences in 2022
While the pandemic is in full swing and having a big impact on the conference circuit, the major C++ events are trying to move to hybrid or return to their offsite venues.
- C++Now, the most academic event in the C++ world, will be happening May 1–6, 2022, in Aspen, Colorado. It will be fully on-site. Submissions are now open through January 30.
- C++ on Sea, a recent event born just before the pandemic set in, also plans to run in-person. The dates have been announced (July 4–7, 2022) along with the keynote speakers (Hana Dusíková, Kevlin Henney, and Jason Turner). If you are interested, submissions are open through February 6.
- C++ Russia, the biggest event in the Russian C++ community, with talks in both English and Russian and quite a few international experts invited, is staying online in 2022. The event has been moved to June 6–9, 2022. The CFP is now open and will be running through March 21.
- C++ North, a brand new Canadian C++ conference, will start for the first time ever on July 17–20, 2022, in Toronto, Canada, as a fully offline event. Sean Parent and Kate Gregory are confirmed as the first speakers, while the general CFP will start January 24.
- ACCU 2022, an event about C++ and much more, will be running a hybrid format April 5–9, 2022. Keynotes will feature Guy Davidson, Hannah Dee, Patricia Aas, and Titus Winters. The rest of the program should be announced soon.
Embedded software development in Visual Studio
A new blog post from Visual Studio describes the updated workflow for embedded development, specifically using the Azure RTOS sample. All the tools necessary for this project can be quickly installed using vcpkg, thanks to the manifest file located in the project folder. Next, the blog post covers code editing, building, deploying, and debugging, while highlighting some of the Visual Studio features. If you have an .svd file from the MCU manufacturer, you can use this description of peripheral registers to get the peripheral register view right in Visual Studio. Another useful view in this case is RTOS Object Views, which has now been added to VS.
CLion 2022 plans and roadmap for 2022.1
The CLion team has decided to fully dedicate the CLion 2022.1 iteration to bug fixes and making a quality improvement release. The announced roadmap describes the key areas of focus:
- Improvements concerning the most recently added remote development and toolchains.
- For embedded developers, the serial monitor plugin will be finalized and the current RTOS debugging support will be improved.
- A handful of the most annoying issues will be addressed in project models, debugger performance, and Clangd stability.
- Users can also expect many improvements to the IDE’s overall performance.
Unreal Engine development on Linux with Rider
A couple of years ago JetBrains started working on a dedicated IDE for developing Unreal Engine games. These efforts targeted Rider, which was known earlier as a C# and Unity IDE. With support for the native uproject project model, we managed to turn Rider into an Unreal Engine IDE, gradually making it available for each of the three major platforms. Windows was the first OS, macOS was added in April 2021, and finally Rider came to Linux in December 2021.
The feature set is similar to what’s available on other platforms, including:
- A smart editor that is knowledgeable not only about C++ in general, but also about the UE reflection mechanism, UE-specific code checks, and the UE naming style.
- Integration with Unreal Editor, which makes it possible to run and debug the game directly from Rider.
- Support for Blueprints, which uses valuable information parsed from BP files to enhance the way code is represented in the Rider editor.
Check out Rider on Linux for your Unreal Engine game development and let us know about your experience. We appreciate all of your feedback, good or bad!