My attempt to simplify C++
Since C++ started to move again with C++11 (no pun intended) we got a lot of new features and abilities in the language. That is great. Of course, not everything we want is already there. Some may never come. Evolving a language is hard. There is only limited time to get new features in, to test them, to improve them. But what I'm telling you, evolving a language is much like improving a software product. Not all feature fit into a release. Some of them are too last minute and may not 100% work as planned. Some may end up being used rarely to never by customers.
However, doing nothing is also not an option. C++ did it for a long enough time.
Like software a language sometimes needs fixes, for the same reasons. What to fix is equally hard to say. Different people have different needs and therefore see different priorities.
My attempt I like to share with you today is making the language a tiny bit simpler. Ironically often when we make things simpler that means we add another way of doing things and by that adding complexity. This is true for my attempt as well.
constexpr class
As I said I like to make one thing simpler and that is a class with only constexpr
member functions. With the evolving C++ standards more and more constructs can be constexpr
. C++20 added a whole new level to this plate with allowing dynamic memory allocations in constexpr
context. We can have virtual constexpr
member functions. Depending on the number of constexpr
member functions we have to write constexpr
all over the place. But for certain constructs the compiler is already able to add constexpr
implicitly. Lambdas or compiler-provided constructors are and example.
With my proposal P2350R0 constexpr class
I aim to simplify such a entirely constexpr
class by instead of having to attribute each member function we can mark the class as constexpr
. This reduces a lot of noise in the class declaration and carries an important message that is otherwise hard to see: this class consists of only constexpr
member functions.
Let's see an example:
1 2 3 4 5 6 7 |
|
This is how some of our classes look these days. In terms of clean code and reducing repetitions constexpr
does a very bad job. We have to write it three times, once for each member function.
With P2350R0 we achieve the same by writing this:
1 2 3 4 5 6 7 |
|
Instead of having to attribute each member function we declare the class itself, in the class-head, as constexpr
. To me this feels much better than what we currently have to write.
XXXX class
One of the early feedbacks I got was, please don't stop at constexpr
also think of other elements. While I listen to this feedback things are not that simple.
consteval class
Let's start with consteval
. It falls right into the constexpr
bucket and is a good candidate for getting added to the class-head like constexpr
. But then we have little to no experience how consteval
will be used. Is there really a need for classes with only consteval
member functions? I don't know. From a standardization and implementation perspective it is like constexpr
and by that doable. But adding something that is not used contradicts the simplifying the language goal.
noexcept class
Another candidate that was mentioned is noexcept
. For sure there are classes out there where each and every member function is marked as noexcept
. Yet, there is a difference to constexpr
. One property of constexpr
member functions is that they must be declared inline. They cannot be split between declaration and implementation. By that the implicitly constexpr
declared members are right in the class with constexpr
at its top. What is the right thing to do for noexcept
function? Is it okay that they are declared implicitly noexcept
and in a cpp-file we may not see it anymore?
There is an interesting difference to constexpr
. If we violate the constexpr
rules the compiler refuses to compiler our code. If we violate the noexcept
guarantee we end up with out application terminating immediately at run-time once we reach that code. Compile-time error vs. run-time error. Whenever I can pick I pick the compile-time error. This makes me less fond of having a noexcept class
.
virutal class
Especially for abstract classes we have a high chance of having virtual
-only member functions. Sometimes if we derive from such a class we end up with only overridden members. A class with all members virtual
would solve the ongoing issues with an unwanted non-virtual
destructor on the base class.
C++ Weekly - Ep 270 - Break ABI to Save C++
I hope you learned something. I appreciate your feedback. Please reach out to me on X or via email.
Andreas