1

Consider a foo.cpp file with the following content

#include "foo.hpp"
int foo() {
    return 7;
}

and its associated header

#pragma once
int foo();

The latter is obviously needed to make aware the following main function of the existence of foo:

#include <iostream>
#include "foo.hpp" // to make the name `foo` available

int main() {
    std::cout << foo() << std::endl;
}

However, the #include "foo.hpp" seems to be redundant. Is there any reason I should keep it?


I've seen this practice in the codebase where I work on, but I guess there's many examples available in open source. For instance, as an example picked at random, look at src/builtin_builtin.h and src/builtin_bultin.cpp from the fish-shell code base: the former, beside the include guard, has just

  1. one #include,
  2. two class declarations,
  3. and a function declaration.

One could put 2 in a fwd header, include it in the cpp file together with 1, and then the cpp file wouldn't need anymore to include its own header.

Enlico
  • 23,259
  • 6
  • 48
  • 102
  • what is a "fwd header" ? – 463035818_is_not_an_ai Aug 05 '22 at 11:05
  • 1
    It's a good way to make sure that the definition and declaration stays in sync (depending on changes can be picked up by a static analyzer, maybe not the compiler itself). It's also a way to add other common structures and declarations or definitions that might be needed (from the Fish files you link to there's for example the `parser_t` and `io_streams_t` types). – Some programmer dude Aug 05 '22 at 11:08
  • when something is necessary in 99% of the cases, its simpler to do the same in 100% of the cases. I'd rather ask "Is there any good reason to remove the include?" Once the source file is modified in a way that needs the header you have to add it anyhow. Imho this boils down to being purely opinionbased. – 463035818_is_not_an_ai Aug 05 '22 at 11:09
  • @463035818_is_not_a_number, I was just curious, but I agree on the "if you do 99, then do 100". As reagrds _fwd header_ I really meant a header that make a declaration of those two classes in the linked example. – Enlico Aug 05 '22 at 11:17
  • 1
    It is common to include the .hpp *first* in the corresponding .cpp file, to see that the header in fact compiles without dependencies. Some people even use an *empty* .cpp file, if necessary, just to perform this test. – BoP Aug 05 '22 at 14:49

2 Answers2

3

C++ processes files in linear order. If your .cpp file calls other methods from the same .cpp file, the definitions need to proceed the calls, else you need the declarations from the .hpp. And with two mutually recursive functions, you do need at least one declaration up front.

Additionally, having class declarations available means that the compiler can warn about mismatches (won't work with free function declarations, due to overloading)

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • *"won't work with free function declarations, due to overloading"* It will work, but only to a limited extend: `double foo() { ... }` would result in a compiler error as would `int foo() noexcept { ... }` or `int __stdcall foo() { ... }` It just cannot check for matching function parameters. – fabian Aug 05 '22 at 15:26
2

Some reasons to include the header (fpp.hpp) from its implementation file (fpp.cpp):

  1. If you include foo.hpp first in foo.cpp, then compilation of foo.cpp acts as a test that foo.hpp is self-contained, meaning it can be successfully compiled without including anything else first. The Google C++ coding guidelines specifically recommend including the associated header first.

  2. It is good practice for foo.hpp to declare everything that foo.cpp exports, and for everything else in foo.cpp to have internal linkage in order to not pollute the global namespace. The GCC option -Wmissing-declarations will report deviations from that practice, but it only works if foo.cpp includes foo.hpp.

  3. Sometimes (often, in fact), including foo.hpp is needed so foo.cpp will compile. Most commonly, foo.hpp defines a type that foo.cpp needs, but it can also happen that function declarations are needed due to use before definition. I recommend to just do so consistently rather than trying to deduce whether it's necessary in each case.

  4. Occasionally, the compiler can diagnose mismatches between declarations and definitions. A nasty case I've seen is a header declaring a global int x but the implementation file defining long x. Waste a day debugging that mistake, and I predict you'll resolve to include the associated header every time thereafter!

Finally, there are no good reasons not to include the associated header. In particular, omitting that include will almost never make a measurable difference to compile time. There are ways of dramatically improving compile times by restructuring header dependencies (for example, use of forward headers), but this isn't one of them.

Acknowledgments: Point 1 was noted by BoP in a comment. MSalters' answer notes points 3 and 4.

Jason
  • 36,170
  • 5
  • 26
  • 60
Scott McPeak
  • 8,803
  • 2
  • 40
  • 79