Transcript
Discussion (0)
Welcome to the C++ Club. This is episode 13 for the meeting number 138 that took place on the 28th
of October 2021. The October committee mailing is out. Papers! First, let's quickly see some of
the papers that have been freshly adopted into C++23. Monadic operations for std optional.
Cy Brand's proposal to add monadic operations to std optional makes it into C++23.
These include map, or as we call it in C++ for some reason, transform, and underscore then, and or underscore else.
Every other language that has an optional concept also has monadic operations for it,
and now so does C++.
You may not want to use these operations, but it's nice to have the option.
See what I did there?
Deducing this.
Quote. We propose a new mechanism for specifying or deducing the value category of the expression that a member function is invoked on.
In other words, a way to tell from within a member function whether the expression it's invoked on is an L value or an R value,
whether it is const or volatile, and the expression's type, end quote.
This is very useful when implementing several overloads of the same member function to deal
with constant ref qualifiers. The proposed syntax is to lift this into an actual member
function parameter so that normal deduction mechanisms could be used.
Add support for pre-processing directives elifdef and elifendef.
This is self-explanatory. I'm surprised it wasn't available before.
Extend init statement to allow alias declaration. In C++20 you can use
typedef in init statement but not using alias declaration. In C++20 you can use typedef in init statement, but not using alias declaration, which is
a bit inconsistent, and this paper fixes it.
Multidimensional subscript operator.
We propose that user-defined types can define a subscript operator with multiple arguments
to better support multidimensional containers and views.
Move-only function.
This paper proposes a conservative move-only equivalent of std function.
Zip.
This paper proposes four new views.
Zip, ZipTransform, Adjacent and AdjacentTransform and related functionality.
The ranges feature gains more useful stuff.
Printing volatile pointers. This fixes a quirk of stream output for volatile pointers which were
being converted to other types like int or bool, because they couldn't be printed as normal const void pointer due to qualifier mismatch.
Byte swapping for fun and enough.
This adds an efficient way to flip or swap or reverse all the bits of an integer type
without having to resort to compiler intrinsics.
Heterogeneous erasure overloads for associative containers.
Quote,
The authors propose heterogeneous erasure overloads
for ordered and unordered associative containers,
which add an ability to erase values or extract nodes
without creating a temporary key type object.
End quote.
Useful. Character sets and encodings.
This is more long overdue improvements to Unicode string support.
What is a view? This paper provides clarifications for the role of views in the ranges feature. The paper really stresses two points throughout.
Views are lightweight objects that refer to elements they do not own,
and views are constant-time, copyable, and assignable.
Support std generator-like types in std format.
This enables formatting results of coroutine-based generator function results by
switching std format to taking parameters by forwarding references instead of const references.
It has been implemented in the fmt library since version 6. It's currently at version 8.
Now some other papers that caught my attention. Standard library modules std and std.compat. Import std std
imports everything in namespace std from C++ headers like stds fopen from CSTDIO. It also imports operator new etc. from the header new.
Import std compat imports all of the above plus the global namespace counterparts for the C wrapper like fopen. I think this paper is on its way to be adopted into C++23.
Distributing C++ module libraries.
Daniel Rosso of Bloomberg proposes a convention
for distributing module-based libraries.
Quote, this paper proposes a format
for interoperability between build tools, compilers,
and static analysis tools that facilitates the adoption of C++ modules,
where libraries are distributed as pre-built artifacts,
as opposed to the build system having access to the entirety of the source code.
End quote.
I can see how big firms need some sort of convention for their internal library distribution.
So this proposal will come handy as long as everyone follows the same convention.
Just like compilers with their C++ module binary interface files.
Oh wait.
Closure-based syntax for contracts.
Gajpa Rajman and his co-authors think that attribute-based contract syntax is too limiting.
They propose a closure-based syntax instead,
with three new context-sensitive keywords, pre-, post- and assert.
The syntax is similar to the require syntax used for concepts.
The authors list some of the advantages of this syntax.
Of the currently proposed attribute-based syntax, of which I especially like this one, quote, it's consistent with the rest of the language instead of inventing
a yet another mini-language, end quote. I can see how this paper has the potential to cause a
non-trivial amount of bike-shedding in the contracts study group. Honestly, after all the
kerfuffle that happened with contracts, where a good enough solution
was derailed at the last minute by those who wanted a perfect one, I lost all emotion towards
contracts and now I'm just watching indifferently from the sidelines.
Let us now look at another area that is totally going super well in the committee.
Networking and senders-receivers.
There are three new papers. Ruminations on networking
and executors. NetTS, ASIO and sender library design comparison. And response to P2464,
the networking TS is baked. P2300, senders-receivers is not. The two sides, networking TS-ASIO and senders-receivers,
are writing letters to each other in the form of proposals.
The saddest thing is the fact that there are two sides.
Nico Agiositis wrote a paper, P2012,
proposing to fix a long-standing problem with a range for loop.
As it stands today, it's really easy to hit lifetime bugs that lead to a crash.
When the expression iterated over contains more than one function call and one of the
functions returns a temporary, its lifetime is not extended, which leads to undefined behavior
the current solution seems to be warning about the possibly UB in code style guides
the MISRA coding standards prohibit more than one function call in the 4-range initializer
the UG votes acknowledged the problem strongly
and were in favor of a solution that could break existing code.
However, UG weren't sure about a new kind of safe loop.
Niko's proposed solution was to add range for loop to the list of cases where lifetime of temporary objects is extended.
Quote,
When a temporary object is created in the for-range initializer of a range-based for statement,
such a temporary object persists until the completion of the statement.
The lifetime of temporaries that would be destroyed at the end of the full expression of the for-range initializer
is extended to cover the entire loop.
On 29 September 2021, the paper got rejected by the committee.
It didn't get enough consensus.
Disappointment was expressed on Twitter.
Necuriosities.
The C++ standard committee just decided they do not want to fix the broken range-based for loop for C++23.
It's broken for 10 years now.
They agree that there is a severe problem, but want a general lifetime solution. But nobody wants to do the work. To which Victor
Zverovich replied, didn't know it was reviewed. Nikoyosotis says, that's the problem with now
standardizing C++ online. Only a few people can always join and rule everything.
To which Victor replies, yeah, it's been a total disaster.
So that's it then.
There is no general lifetime solution and the range-for loop stays broken in subtle
ways.
Stringy templates Colby Pike, aka VectorofBool, wrote an article on his blog about using strings as template
parameters.
This is a feature of C++20 called non-type template parameters.
An integer template parameter results in a new type for each value of the parameter.
This has been supported for a long time. In C++20
we can use a class type non-type template parameters. Certain requirements
have to be met by such class. All its members can only be of type valid as
non-type template parameter or an array of such type. Colby Pike uses it to
implement a fixed string template combined with a deduction guide
it allows for an easy initialization
that looks like a normal assignment
fixed string equals hello
whereas the type of the template is an array of characters
now that we have a string class that can be used as a template parameter,
we can do interesting stuff like what Colby Pike calls stringy templates. You can implement name
types with the name of the type represented by a string as a template parameter and make it so
that you can only assign a certain type to instances of such a template.
This is very interesting and I'll be watching for further posts on this topic.
The code is available on GitHub.
The Reddit thread mentions two projects that use similar techniques.
Constaval Huffman, a C++20 utility for compressing string literals at compile time to save program space.
And CTRE.
Fast compile time regular expressions with support for matching, searching, capturing
during compile time or runtime.
There is a third project called Metama, row polymorphism in C++20.
This post is an attempt at implementing Haskell-type extensible records in C++20.
The code is on GitHub.
The author uses the cutting-edge Visual Studio 2022 Preview 5 for development.
Quote,
Row polymorphism is a kind of polymorphism that allows one to write programs that are
polymorphic on record field types, also known as rows, hence the name."
This is like prototype-based inheritance in JavaScript, where you inherit objects instead
of types, and then extend them by adding fields.
The author uses a fixed string class, just like Colby Pike in the previous article.
And that is it for today and I'll leave you with this tweet by Ben Porter.
Quote, I'll sometimes leave a dangling else just as a threat to the compiler
that it better run that if statement or else. Thanks for coming and I'll talk to
you next week. Bye!