c++includeheader-filesdeclarationtranslation-unit

Is there any reason I should include a header in the associated cpp file if the former only provides declarations the latter defines?


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.


Solution

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