There are workarounds like pimpl (aka. C style encapsulation). But this requires extra boilerplate and indirection. C++ modules might fix it at some point, but after 35 years of not having them in C++ most real life codebases aren't set up that way and may never be.
If the compile time (when adding a method) is really an issue you can chop up and reconfigure your include files. A pain, but perhaps saves you time in the long run.
Of course (waves hands) modules will magically improve things...someday.
Haven't you ever seen someone do
struct Thing;
struct OtherThing;
in lieu of just including "thing.h"? I see it frequently in real life code bases and I can't see a reason for it other than compilation time optimisation.Hmm, there might be some interesting linker hacks to patch things up post compilation. But then you'd want some way to do the forward declaration for cases where Thing could have been passed in registers...
Even worse, this dependency is transitive. Dependencies to allow defining these private methods an fields are exposed too, forcing inclusion of headers to all members of the class, even if it's only implementation details.
>> under what circumstances does (2) hold?
To add a private member variable or function, you need to put it in the class definition in the header file. Then anything that includes the header needs to be recompiled.
But even if you managed to do that, first compilation is still much slower than it should be, because anlot of headers have to be included (transitively) to allow even declaring these fields and methods.
Thinking about that, is there any case in which private functions can end up in a vtable? In that case, it'd break ABI too.
Yes, but it generally isn't something that is done.