C++ – Ensuring Headers Are Explicitly Included in CPP Files

ccoding-styleinclude

I think it's generally good practice to #include the header for any types used in a CPP file, regardless of what is already included via the HPP file. So I might #include <string> in both my HPP and CPP, for example, even though I could still compile if I skipped it in the CPP. This way I don't have to worry about whether my HPP used a forward declaration or not.

Are there any tools that can enforce this #include coding style? Should I enforce this coding style?

Since the preprocessor/compiler doesn't care whether the #include is coming from the HPP or CPP, I get no feedback if I forget to follow this style.

Best Answer

This is one of those "should" rather than "shall" kinds of coding standards. The reason is that you would pretty much have to write a C++ parser to enforce it.

A very common rule for header files is that they must stand by themselves. A header file must not require that some other header files be #included before including the header in question. This is a testable requirement. Given some random header foo.hh, the following should compile and run:

#include "foo.hh"
int main () {
   return 0;
}

This rule has consequences with regard to use of other classes in some header. Sometimes those consequences can be avoided by forward declaring those other classes. This isn't possible with a lot of the standard library classes. There's no way to forward declare a template instantiation such as std::string or std::vector<SomeType>. You have to #include those STL headers in the header even if the only use of the type is as an argument to a function.

Another problem is with stuff that you incidentally drag in. Example: consider the following:

file foo.cc:

#include "foo.hh"
#include "bar.hh"

void Foo::Foo () : bar() { /* body elided */ }

void Foo::do_something (int item) {
   ...
   bar.add_item (item);
   ...
}

Here bar is a class Foo data member that is of type Bar. You've done the right thing here and have #included bar.hh even though that would have to have been included in the header that defines class Foo. However, you haven't included the stuff used by Bar::Bar() and Bar::add_item(int). There are many cases where these calls can result in additional external references.

If you analyze foo.o with a tool such as nm, it will appear that the functions in foo.cc are calling all kinds of stuff for which you haven't done the appropriate #include. So should you add #include directives for those incidental external references foo.cc? The answer is absolutely not. The problem is that it is very hard to distinguish those functions that are called incidentally from the ones that are called directly.