Two more musings on Clang diagnostics

As of this writing, Chris Di Bella is running a survey on /r/cpp asking what are the biggest pain points with Clang’s diagnostics. In the free-form text entry field, I made two observations, which I’m now expanding into a full-fledged blog post. (Don’t worry — I didn’t type all this into that Google Forms survey!)

The humble potato

From Blackwood’s Magazine, November 1819:

PSA: ADL requires that unqualified lookup has found a function

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.”

Larson wine limericks

Last month I and some family members entered the Larson Family Winery’s annual St. Patrick’s Day limerick contest. Here are our also-rans (the first by my mom, the others by me):

Kafka, math jokes, triangle dissection

The other week, I attended a book club on Kafka’s short story The Burrow. It’s a quite frankly brilliant portrayal of neuroticism. The titular burrow reads like a metaphor for so many things at once: a house, a body of work, a life history. The story (translated by Willa and Edwin Muir) is quotable and yet, somehow, no pull quote could be satisfactory; all I can recommend is that you go read it!

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.

History of non-standard-layout class layouts

Thanks to Jody Hagins for inspiring this blog post, for digging up some old wordings, and for reviewing a draft of this post. Also thanks to Pal Balog for P1847; its historical details were indispensable in writing this post.

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.

Evirdle

Has it been a week since Birdle already? Wow. Anyway, I’ve made another Wordle variant. I call this one Evirdle, because it is evil. It tries to make your Wordle experience as challenging as possible.

Birdle

From the “committing to the bit” department, I present: Birdle.

“Universal reference” or “forwarding reference”?

Two convergent observations from my corner of the C++ world:

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.”

2. Multiple C++ learners (or perhaps intermediate-level C++ programmers having a senior moment) asking whether there’s an easy way to pass an rvalue expression to a function expecting a const lvalue reference.

A minimally interesting typo-bug

I just ran into some code like this in a test suite:

struct MoveOnlyWidget {
MoveOnlyWidget(int);
MoveOnlyWidget(const MoveOnlyWidget&) = delete;
MoveOnlyWidget(MoveOnlyWidget&&) = default;
MoveOnlyWidget& operator=(const MoveOnlyWidget&) = delete;
MoveOnlyWidget& operator=(MoveOnlyWidget&&) = default;
MoveOnlyWidget() = default;
};


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?

Last week someone posted a /r/cpp thread titled “Declaring all variables local to a function as const”:

Ok, so I’m an old-school C++ programmer using the language now since the early ’90s. I’m a fan of const-correctness for function and member declarations, parameters, and the like. Where, I believe, it actually matters.

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.

Intellectually, I understand the (what I consider mostly insignificant) arguments in favor of this practice, but in nearly 30 years I have never had a bug introduced into my code because a local function variable was mutable when I didn’t expect it. It does nothing for me to aid in code analysis or tracking. It has at most a tiny impact on performance.

Maybe I’m just an old dog finally unable to learn a new trick. So, on this fine Wednesday, who’s up for a religious war? What are y’all doing?

TLDR: I’m not putting const on all the things, either.