9

I ran into a situation where my build speeds have started to become large and have affected productivity. I had already minimized header dependencies before using forward declarations. Now I've turned to forward declarations to further reduce these dependencies as a method of trying to reduce compile times.

I understand the concept of forward declarations, but I didn't quite understand how much you could forward declare until I came across this. As I understand it, I can forward declare all method/function parameter and return types for function declarations.

I have a lot of situations where I have (assume I have include guards in header):

//myclass.h
#include "someclass.h"
#include "someotherclass.h"

class MyClass{
public:
    SomeOtherClass foo(SomeClass y);
};

With forward declarations, I can now do something like:

//myclass.h
class SomeClass;
class SomeOtherClass;

class MyClass{
public:
    SomeOtherClass foo(SomeClass y);
};
//include actual header files in myclass.cpp

I believe this will require the header to be included at the call site some how, but removes the include from the header. And the caller doesn't use that call, I would assume It would just be a net gain of needing that dependency at all on the call site.

I haven't seen this pattern before (only with class members and private function types), so I'm wondering if there is any downside to doing this. Is there a reason why I shouldn't just forward declare all of these types?

5
  • 1
    @DocBrown My concern is that there is some non compiler related reason why I might want to avoid this. I've never seen a library which didn't include the types necessary to run the functions it defines, at least not on public facing functions. Is there an argument made to the usability cost of creating all of these incomplete types required to run library functions?
    – Krupip
    Mar 20, 2019 at 21:37
  • Naive question: instead of spending expensive time on reengineering declarations,wouldn’t it be more productive to invest in more performant hardware ?
    – Christophe
    Mar 21, 2019 at 8:46
  • I feel this is a badly phrased question. By asking it so specifically in the negative you are preventing people from giving the best answers to the question: you should forward declare by default and avoid it only in rare situations. There are reasons not to but they're not sufficient to recommend against. Mar 21, 2019 at 9:25
  • I can't advise against their usage despite what Google Style Guide says.
    – R Sahu
    Mar 23, 2019 at 5:50
  • 1
    Related: stackoverflow.com/q/9906402/509868
    – anatolyg
    Mar 28, 2019 at 12:26

1 Answer 1

14

Yes, at least one reason exists.

The Google Style Guide acknowledges that forward declarations can improve compile time, but still advises developers to prefer #include declarations when possible (especially when using third-party libraries), and lists some reasons why:

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

There are, of course, dissenting opinions elsewhere on the Web. Most reasonable[citation needed] treatments of the subject admit there are benefits and drawbacks to either approach, and so, as usual, it's a judgment call whether to use or not use this tool in any given situation.


These are not the only articles written on the subject, nor are they authoritative. They're just two relevant pages I happened to stumble across (one of them being a response to the other); there is of course a much wider debate to be found, if you care to look.

This answer was written primarily by just copying information from other sites. The search terms I plugged into Google were:

"c++" "do not use forward declarations"

This got me a decent list of sites on page 1 that could be skimmed to pick out what the conventional wisdom might indicate are the pros and cons of this language feature.

You can try these and other terms and search query formats to find controversy over the use of lots of other optional language tools, too; my personal favorite currently happens to be generics (if they're in Go 2, I will continue using Go 1 as long as it's still supported, and then probably find a different favorite language).

6
  • 11
    Generally, citing the Google Style Guide as an authority for anything will incite controversy, as many with good reason see it as an unconscionable violation of any attempt to write good code. At least, in this case the decision section is acceptable, even if it can be summarized thus: Only forward-declare entities from the same project, and even then sparingly. As an attempt at properly representing it, you should have included the other two sections (Pros+Decision), which as shown makes this point more reasonable. Mar 20, 2019 at 22:46
  • 1
    I agree it's controversial (and for that reason included a dissenting opinion even though it doesn't directly help answer the question that wasn't asked). I think I disagree with the decision, even though I haven't needed to care that much in a while (my current team uses Go in all the places we might've otherwise used C++). Still, in the interest of answering "are there any reasons not to...?", a popular(-ish) guide listing those reasons seems like a relevant link to me. ¯_(ツ)_/¯ Mar 20, 2019 at 22:51
  • 4
    Most points in that Google Style Guide are very weak or strawman arguments, especially the one about undefined behaviour. Mar 21, 2019 at 6:52
  • 2
    "Forward declarations can hide a dependency, allowing user code to skip necessary recompilation when headers change." I think this is actually incorrect. I think it is impossible for a forward-declaration to hide a compilation dependency. Or somebody please correct me if I'm wrong. What a forward-declaration can hide is a link-dependency. But we're already supposed to write our build-scripts to be smart enough to relink when necessary, so avoiding forward declarations as a way to prevent stale linkage is a hack. Nov 30, 2020 at 20:48
  • 1
    I also came to ask how they could possibly hide a dependency, I think @KeithRussell is correct. May 4, 2021 at 20:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.