-1

Fact: Forward declarations (of class-types) are to be preferred over includes.

Is there a downside to forward-declaring everything in a header and including that header? (I'm guessing the compilation time shouldn't increase by a lot)

In large codebases, forward-declarations can take up to a lot of screen-space, and it would be cool to replace them with a single include - however, it doesn't make sense to have a forward-declaration header for each header with forward declarations.

Has anyone done this or seen this before?

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 3
    The "fact" is rather doubtful, especially with modern development tools that support precompiled headers. – Sergey Kalinichenko Oct 04 '12 at 13:54
  • @dasblinkenlight compilation time is not the only aspect taken in consideration. – Luchian Grigore Oct 04 '12 at 13:56
  • What else is there in favor of forward declarations vs. including a file?.. – Sergey Kalinichenko Oct 04 '12 at 13:59
  • @dasblinkenlight: precompiled headers don't help you when you change a header file that is included everywhere, directly or indirectly. – interjay Oct 04 '12 at 13:59
  • @dasblinkenlight http://stackoverflow.com/a/9906429/673730 – Luchian Grigore Oct 04 '12 at 14:01
  • That answer lists downsides to poorly structured include files, rather than upsides to forward declarations. The biggest disadvantage to forward-declaring outside of an include file is a very real possibility that the real definition will diverge its copy. – Sergey Kalinichenko Oct 04 '12 at 14:07
  • @dasblinkenlight not really, unless you call a header that includes other headers as poorly structured, which would render the argument invalid. Why pollute the namespace for nothing. If you don't need a full definition, why have it? – Luchian Grigore Oct 04 '12 at 14:09
  • "If you don't need a full definition, why have it?" Absolutely, that's what I call a poorly structured header. If you do not need a full declaration, do not use an `include`, and use a forward declaration in the header instead. But that recipe is not universal: in particular, it does not work on free-standing functions. It works well for classes, but it's certainly not for "everything". – Sergey Kalinichenko Oct 04 '12 at 14:16
  • The phrase "a forward-declaration header for each header with forward declarations" is a little confusing. Maybe "a forward-declaration header for each header" would be clearer, if that is what you mean. – Vaughn Cato Oct 04 '12 at 14:17
  • @dasblinkenlight OOOOOOOOO okay sorry - missunderstanding. I'm talking about classes here. :) – Luchian Grigore Oct 04 '12 at 14:17
  • @dasblinkenlight that's because you declare a function and forward-declare a class. I know forward-declare and declare a class are the same, but I'm sure you understand what I mean. (just the lingo) – Luchian Grigore Oct 04 '12 at 14:19
  • Oh, OK, the trick works very well for classes! – Sergey Kalinichenko Oct 04 '12 at 14:20
  • If you need a lot of forward declarations, it does raise the question of whether you are doing too much in one source file. – Vaughn Cato Oct 04 '12 at 14:31
  • @VaughnCato oh, **I know I am**. Sometimes, there's just nothing you can do ;) – Luchian Grigore Oct 04 '12 at 14:32
  • 1
    `"however, it doesn't make sense to have a forward-declaration header for each header"` -> why do you think it doesn't make sense? In my opinion, this is the cleanest approach: if I need the full definition of `Foo`, then I include `Foo.hpp`; if I only need its declaration, then I include `Foo_fwd.hpp`. This way, correctly declaring the class is the responsability of the library containing `Foo`, allowing me to ignore implementation details (how many people tried to forward declare `std::vector` and failed..?). As a matter of fact, this approach is used in some Boost libraries. – Luc Touraille Oct 04 '12 at 15:21

3 Answers3

2

I think without going to extremes there are hardly any downsides to forward includes.

I personally wouldn't care about the screen space. It sure beats multiplying build times by 2 to 5 to 10. We used to have build times upwards of around 2 hours.... Some extra forward includes could have eliminated the same file getting hit thousands of times.

Anyways, you can't always use a forward declaration for everything. If you are sub-classing something, than you have to have the class definition, and that could mean an include. That's fine.

One thing you can do, to remove dependencies is to de-inline your code in your header files. Make sure to push interfaces up, and implementations down (See C++ coding standards by Sutter and Alexandrescu). Meaning prefer for your public API's to be abstract interfaces if possible. If you can do that, than the amount that you need to include or forward declare can be minimized.

Oh and also don't put hundreds of functions and classes in one header file so it's 8000 lines long. No one can read / comprehend such files.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
C.J.
  • 15,637
  • 9
  • 61
  • 77
  • Please stick to the question. Other to the first sentence, there's nothing useful in the answer (related to the question that is). – Luchian Grigore Oct 04 '12 at 14:03
  • I completely disagree. I thought it was completely relevant to minimizing types needed to compile. If you minimize those, you can minimize the includes and your forward declarations, something you mentioned you were concerned about. – C.J. Oct 04 '12 at 14:08
1

I usually do so in my projects. But I split forward declarations in modules. For example: gui, core and so on. That gives a good balance between recompiling a lot because of using includes in headers and between writing forward declarations manually

Andrew
  • 24,218
  • 13
  • 61
  • 90
1

One of the main benefits of using forward declaration instead of includes is that you don't need to recompile as many source files whenever you change a header file, since that header file will only be included where it is actually needed.

Your approach can reduce this benefit, and in some cases even make it worse: Every time you add or remove a class somewhere, you will need to change your global header file that contains the forward declarations. And then you will need to recompile every source file in your codebase, including the ones that don't use the added class.

Still, since classes probably aren't added too often, maybe this isn't too bad a tradeoff.

interjay
  • 107,303
  • 21
  • 270
  • 254