Search code examples
c++includeheader-files

What am I able to (not) include in a .cpp file?


This question is pretty weird. Say I have a file, called idiot.cpp, and it begins with:

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <string>
#include <set>
#include <exception>
#include <iostream>
#include "idiot.h"

and I have a header file, idiot.h. First of all, in idiot.h, do I also have to insert

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <string>
#include <set>
#include <exception>
#include <iostream>

or do I not? Second, if I have another source file, say, "bonito.cpp," that uses idiot.h, should I just #include "idiot.h", or should I paste in the code snippet again? If not, is there any way to shorten this so I don't end up including around 20 headers per file? (hypothetically) Sorry if this is a pretty dumb question, but I don't use many headers too often.


Solution

  • idiot.cpp does not need to include anything included indirectly by idiot.h to be able to compile.

    The more interesting case: bonito.cpp #includes idiot.h and idiot.h includes x.h. If idiot.h only uses the content of x.h for private or anonymous namespace code - and bonito.cpp wants to use something from x.h too, then bonito.cpp should include x.h directly (redundantly).

    The justification is simple: idiot.h can't remove something from the public/protected interface without risking breaking client code, so if that happens then the clients have to expect to deal with it - possibly including an extra header too. BUT, the maintainer of idiot.h and idiot.cpp should be free to change private or anonymous namespace content within idiot.h without risking breaking client code, including which headers are included to support that private code.

    So, the inclusion is redundant at the time it's done, but that's done in the expectation that it might stop being redundant as idiot.h evolves.

    This best-practice model is not automatically enforced - you have to understand the way this should work and actively code to that model.

    Example

    If idiot.h contains...

    #include <string>
    #include <vector>
    ...
    class X {
        void add(const std::string&);
      private:
        std::vector<std::string> v_;
    };
    

    ...then bonito.cpp can reasonably use std::string without including <string>, but should include <vector> itself if it needs std::vector<>.