Only a handful of commenters have mentioned "#pragma once", which is alarmingly few people considering how many C++ practitioners are out there. "#pragma once" is the obvious way to deal with this problem.
That's a somewhat unrelated problem, it just protects from parsing the same header multiple times. The rule that headers should not include other header is more of an organizational thing.
You can immediately see the include complexity of each source file by looking at the top of the file, all required includes are there as a flat list. Otherwise a single #include may hide dozens, hundreds or even thousands of other includes hidden in a deep dependency tree.
It also nudges the programmer away from "every class in a tiny header/source pair" nonsense.
`#pragma once` isn't standardized. Even though all major modern compilers do support it (hopefully, but not guaranteed in the same way), if you care about portability to some not even very esoteric platform, it most likely uses ancient compilers (or based on ancient version of a major compiler) that might not support it.
But besides that I too don't see a reason why not use a better `#pragma once` instead if include guards...
Pragma once is a defacto standard and is supported by every compiler and platform you’re ever going to work with. If you need to support the targets it doesn’t work with, then you’ll get a loud compile error.
The old include guards are error prone, requiring a unique key per header. Getting that wrong can cause anything from a compile error, an obtuse linker error, or a runtime bug depending on what’s in the header.
The chances of someone copy pasting a header and breaking the include guard are significantly higher than the chances of someone deciding that we need to support an esoteric embedded target overnight.
This. #pragma once is more consistently supported than many parts of the standard. Just use it. (And I've worked with some of those esoteric embedded targets. Haven't run into a compiler that didn't support it yet)
FWIW I've never seen a compiler that doesn't support '#pragma once' (at least since the late 90s).
I did come across some esoteric path-related problems with pragma once though which wouldn't occur with include guards. IIRC it was related to filesystem links.
I've come across obscure bugs with header guards in open source software that went unnoticed for years -- essentially, there were competing definitions of a global config struct in the code base. Some parts of the code would access Version A, while others would access the same data but thinking it was version B.
Most .c files had ended up including both versions, but the headers had the same guards so only the first included definition would be in effect.
The project maintainer had been fixing obscure memory bugs for years until someone noticed the real issue.
Wouldn't have happened with #pragma once I suppose. With pragma once you don't have to painfully choose an identifier for the header guard, and you can't get that wrong.