Not to say that the Google Style Guide is the holy bible but as a newbie programmer, it seems like a good reference.
The Google Style Guide lists the following disadvantages of forward declaration
Forward declarations can hide a dependency, allowing user code to skip necessary recompilation when headers change.
A forward declaration may be broken by subsequent changes to the library. Forward declarations of functions and templates can prevent the header owners from making otherwise-compatible changes to their APIs, such as widening a parameter type, adding a template parameter with a default value, or migrating to a new namespace.
Forward declaring symbols from namespace std:: yields undefined behavior.
It can be difficult to determine whether a forward declaration or a full #include is needed. Replacing an #include with a forward declaration can silently change the meaning of code:
Code:
// b.h:
struct B {};
struct D : B {};
// good_user.cc:
#include "b.h"
void f(B*);
void f(void*);
void test(D* x) { f(x); } // calls f(B*)
If the #include was replaced with forward decls for B and D, test() would call f(void*).
Forward declaring multiple symbols from a header can be more verbose than simply #includeing the header.
Structuring code to enable forward declarations (e.g. using pointer members instead of object members) can make the code slower and more complex.
However, some search on SO seemed to suggest that forward declaration is universally a better solution.
So given these seemingly non-trivial disadvantages, can someone explain this discrepancy?
And when is it safe to ignore some or all of these disadvantages?
some search on SO seemed to suggest that forward declaration is
universally a better solution.
I don't think that's what SO says. The text you quote is comparing a "guerilla" forward declaration against including the proper include file. I don't think you'll find a lot of support on SO for the approach Google is criticising here. That bad approach is, "no, don't #include
include files, just write declarations for the few functions and types you want to use".
The proper include file will still contain forward declarations of its own, and a search on SO will suggest that this is the right thing to do, so I see where you got the idea that SO is in favour of declarations. But Google isn't saying that a library's own include file shouldn't contain forward declarations, it's saying that you shouldn't go rogue and write your own forward declaration for each function or type you want to use.
If you #include
the right include file, and your build chain works, then the dependency isn't hidden and the rest of the problems mostly don't apply, despite the fact that the include file contains declarations. There are still some difficulties, but that's not what Google is talking about here.
Looking in particular at forward declarations of types as compared with class definitions for them, (4) gives an example of that going wrong (since a forward declaration of D
cannot express that it's derived from B
, for that you need the class definition). There's also a technique called "Pimpl" that does make careful use of a forward type declaration for a particular purpose. So again you'll see some support on SO for that, but this isn't the same as supporting the idea that everyone should in general run around forward-declaring classes instead of #include
ing their header files.
From Titus Winters' CppCon 2014 talk:
The big one that we've learned lately is: Forward declaring anything with a template in it is a really bad idea. This led to maintenance problems like you would not believe. Forward declaration may be okay, in some cases? My suspicion is the rule is actually going to change to: Library owners are encouraged to provide a header that specifically forward declares the things that they think are worth it (emphasis added), and you probably shouldn't forward declare yourself, and nobody should ever forward declare a templated type. We'll see. We're still working out the [inaudible] details from what we've learned.
So maybe issues with trying to directly forward declare templated types might be one of their motives for discouraging forward declaration wholesale...?
Also, providing "a header that specifically forward declares the things that they think are worth it" sounds similar to the way <iosfwd>
is used, as described here (Solution 2.2), here, and here.
EDIT:
To be clear, I wasn't saying I agree or disagree with Google's discouragement of forward declaration. I was just trying to understand their rationale, and made an aside/observation about <iosfwd>
.
Personally, I use forward declarations whenever I can, following the guideline stated later in that same GOTW linked above (Solution 3):
Guideline: Never #include
a header when a forward declaration will suffice.
but Winters' reasoning seems to have some merit as well. I've worked on code where I forward declared templated types from a third party library, and the syntax does get messy (I haven't yet run into the maintenance problems Winters alluded to). OTOH, I'm not so sure about discouraging all forward declarations as stated in the Google C++ Style Guide, but I guess that's what works for Google?
Disclaimer: I'm no expert, still learning.