Sometimes the small changes between two C++ standards really bite you. Today's post is about when I got bitten by a change to aggregates in C++20.
A harmless example
Attendees of my training classes usually assume that I know everything. I can say sorry, but that's not the case. One day in the past, I showed the following example during a class:
1 2 3 4 5 6
The class did cover C++17 and C++20. The code of
Point is a reduced version for this post. We were talking about C++17's structured bindings. I use
Point to show the decomposition using C++ Insights.
I showed the behavior and certain variations while answering questions from the attendees. One question was about move and copy. The question leads me changing the initial code to the following one:
1 2 3 4 5 6 7 8
As you can see, in A, I deleted the move constructor. As far as I remember, this topic was more or less the last one for this day. Everything went well and as expected.
Works on my machine
The next morning one of the attendees approached me with the question of why the code didn't compile on his machine. My usual answer here is that if C++ were be easy, I wouldn't have the job I have. Somehow this never shuts down such questions. I like curious attendees.
He shared his code via Compiler Explorer. Guess what? His code looked exactly like mine but didn't compile. Here is the error message from the compiler:
1 2 3 4 5 6 7 8 9 10 11
Rules for aggregates
Do you remember that I told you the class did also cover C++20? Since structured bindings have been introduced with C++17, my example did use C++17. Since the bug reporter also played with C++20 features, his environment was set to C++20.
What should I say? The code no longer compiles in C++20. The reason is that in C++20, an aggregate cannot have a user-declared constructor, among other restrictions. This was the case before C++11 but was changed with C++11 and once more with C++20.
Due to that change,
Point is no longer an aggregate; hence, the compiler does not accept the initialization of
Point as no constructor is present.
Be aware of the small changes between the standards. While I think the C++20 behavior is correct, I still wrote that piece of code. It is unlikely that I would write such code in production, but you never know.
If you want to know more about aggregates and PODs, check out my post C++20: Aggregate, POD, trivial type, standard layout class, what is what.