C++20 Serves Up Intriguing Embedded Features


What you’ll learn

  • New features in C++20
  • What is important for embedded developers

 

C remains the darling of embedded programmers, but C++ garners a sizable chunk. Using C++ features judiciously can result in code that’s as efficient or more efficient than a comparable C application. The comment about a more efficient implementation is because it can be tedious to do some implementations in C that are more easily done with C++’s advanced features, and if we’re talking about a typical developer doing the coding.

C++20 is the seventh iteration of C++ that has been preceded by the likes of C++17, C++14 and C++11. Each added new features and trashed a couple along the way. For example, the auto keyword was a new feature in C++14. C++11 was where significant changes were made, and it’s one of the more common versions employed in embedded systems. Embedded developers aren’t known to ride the cutting edge when it comes to their tools. Proven and reliable hold greater importance when developing a platform that may need to run for decades.

As it turns out, C++20 is adding quite a few new features. The new iterator ranges and string formatting support will be generally useful along with a new synchronization library. It is often called the three-way comparison operator. As with most features, the description of the spaceship operator is beyond what we can pack into this article but in general a comparison like x will be first be converted to x.operator(20) . This means comparison support can be done by writing one or two operator functions rather than the dozen or so to handle the operators like =, and >. The expression x == y transforms to operator(x, y) == 0.

But onto more interesting things.

The features I think will be of interest to embedded developers include:

  • Explicit constants
  • Coroutines
  • Concepts, experimental
  • Modules

Explicit constants

Embedded developers like things that can be done at compile time rather than run time. C++11 added the constexpr keyword, allowing functions to be defined as compile time computation. C++20 allows this feature to be used with virtual functions. It can even be used with try/catch. Of course, there are some exceptions.

The new consteval keyword is a twist on contexpr. That essentially makes it an alternative to macros, which, along with #define constants, are the bane of C and C++.

Coroutines

Coroutine support is often provided by runtimes and some operating systems. Coroutines provide a voluntary form of multitasking and can simplify the implementation of state machines and other applications like a voluntary round robin scheduler. Essentially, a task explicitly yields control and will eventually be restarted at that point.

The coroutine_traits and coroutine_handle provide support for coroutines in C++20. Coroutines are stackless and usually allocated from the heap. A coroutine can yield control and optionally provide a result to the coroutine task being resumed.

Concepts and Constraints

Concepts and constraints were an experimental feature in C++17 and are now standard, so we may assume the experiment succeeded. If you were hoping for Ada and SPARK contracts, that’s not the case, but concepts and constraints in C++20 are valuable additions.

On the plus side, constraints can detect errors at compile time. Class templates, function templates, and non-template functions can have a constraint attached to them. The constraint is a predicate that’s evaluated at compile time. A named set of these definitions is called a concept. This sample code from cppreference.com highlights the syntax and semantics of this feature:

#include 
#include 
#include 
using namespace std::literals;
 
// Declaration of the concept "Hashable", which is satisfied by
// any type 'T' such that for values 'a' of type 'T',
// the expression std::hash{}(a) compiles and its result is convertible to std::size_t
template
concept Hashable = requires(T a) {
    { std::hash{}(a) } -> std::convertible_to<:size_t>;
};
 
struct meow {};
 
template
void f(T); // constrained C++20 function template
 
// Alternative ways to apply the same constraint:
// template
//    requires Hashable
// void f(T); 
// 
// template
// void f(T) requires Hashable; 
 
int main() {
  f("abc"s); // OK, std::string satisfies Hashable
  f(meow{}); // Error: meow does not satisfy Hashable
}

It’s one of the more significant features in C++20 that addresses applications requiring safety and reliability. This includes application spaces like automotive, avionics, and medical.

Modules

The ubiquitous #include is being replaced by modules. The import and export keywords are found where the #include once resided.

The #include made compilers easy to write. They just start reading from another file, and it’s as if the included file was part of original file. This approach depended on the order in which files were combined. While workable, this doesn’t scale well when dealing with large, complex systems, especially with all of the relationships that C++ templates and classes can bring to the table.

Module-based build systems are common, and languages like Java and Ada already employ a similar system. Essentially, the module system allows modules to be loaded once within a compile even if they’re used by multiple modules. Module importing order isn’t a problem. Likewise, modules can explicitly expose their internals, which isn’t possible with #include.

The existing standard libraries will now support inclusion as modules, but backward compatibility requires the #include support to remain. Modules work well with the existing namespace support. C++11 introduced inline namespaces.

I’m still biased toward programming with Ada and SPARK, but the new changes in C++20 make it a better C++ platform for developing safe and secure software. I actually need to play with the new C++20 features to see how they impact my programming style. I tended to avoid coroutines since they were non-standard. Though concepts and constraints are going to be a bit more challenging, they will be more useful in the long run.

On the plus side, the open-source compilers support C++20 and more commercial versions are coming online.



Source link