page = arthur o'dwyer – stuff mostly about c++
url = https://quuxplusone.github.io/blog
This is yet another followup to “What is the std::swap two-step?” (2020-07-11) and “PSA: ADL requires that unqualified lookup has found a function” (2022-04-14), as my mental model continues to evolve. (Mainly due to pressure from Jody Hagins. :))
As seen on the cpplang Slack (hat tip to Jody Hagins). Recall my post “What is the std::swap two-step?” (2020-07-11), where I said:
A qualified call like base::frotz(t) indicates, “I’m sure I know how to frotz whatever this thing may be. No type T will ever know better than me how to frotz .”
An unqualified call using the two-step, like using my::xyzzy; xyzzy(t) , indicates, “I know one way to xyzzy whatever this thing may be, but T itself might know a better way. If T has an opinion, you should trust T over me.”
An unqualified call not using the two-step, like plugh(t) , indicates, “Not only should you trust T over me, but I myself have no idea how to plugh anything. Type T must come up with a solution; I offer no guidance here.”
TIL: nullopt_t is not equality-comparable, but monostate is
On Slack , Kilian Henneberger asked for some STL types that are copyable but not equality-comparable. One example is std::function<int()> ; see “On function_ref and string_view (2019-05-10). The simplest example is struct S {}; — for compatibility with C, C++98 provided every class type with a copy constructor, but none of them with comparison operators.
What if vector<T>::iterator were just T* ?
Every major C++ standard library vendor defines wrappers for their contiguous iterator types — vector<T>::iterator and so on. You might think that they should just define these iterators as aliases for T* instead.
1. Multiple book authors pushing the idea that Scott Meyers’ original phrase “universal reference” (for T&& ) is actually preferable to the now-Standard term “forwarding reference.”
volatile means it really happens
During my CppCon 2020 talk “Back to Basics: Concurrency,” someone asked, “Do we ever need to use volatile ?” To which I said, “No. Please don’t use volatile for anything ever.” This was perhaps a bit overstated, but at least in the context of basic concurrency it was accurate. To describe the role of volatile in C and C++, I often use the following slogan:
Marking a variable as volatile means that reads and writes to that variable really happen.
If you don’t know what this means, then you shouldn’t use volatile .
const all the things?
Now we have a team member who has jumped on the “everything is const” bandwagon. Every code review includes dozens of lines of local function variables now declared const that litter the review.
TLDR: I’m not putting const on all the things, either.
Here’s a C++ riddle for you: When does std::invoke not invoke?
Given this code ( Godbolt ), libc++ and Microsoft accept the call to invoke , but libstdc++ rejects with a spew of errors: