1

In a large Qt project in which a lot of Qt and project headers are included in every file, it is easy to:

  1. include extra Qt files that don't need to be included because they are already included in another Qt file (for example, qbytearray.h is included in qstring.h).
  2. forget to include needed Qt files because they are already included in other included project files (for example, the compiler finds qstring.h included in another of your files and doesn't complain).
  3. left included extra Qt files that are not needed anymore after a modification.

I have been also reading that, even with modern compilers, it is better to include the files needed, and only those, instead of the easy way of including more generic headers like QtCore and QtGui.

The rule seems easy: include only everything you need and don't depend on other included files in case they change in the future (for example, qstring.h could not use qbytearray.h anymore, which is also true for project files), but it's not so easy to achieve. And Qt Creator doesn't help much with that, because when you begin to write QStr... it auto-completes with QString and compiles, and you don't even wonder why nor think of including the header.

Is there a list of Qt headers dependencies or an automatic Qt tool or a rule or something to make sure I have chosen all the headers I need and nothing else? The question is general to C/C++, a way to get the optimum header dependency.

AAEM
  • 1,837
  • 2
  • 18
  • 26
  • 2
    Unfortunately you just have to read the code. See what it uses. Know what headers provide that. Then edit the source to include just what you need. There's (to my knowledge) no tool or other magic available to do it for you. – Jesper Juhl Oct 12 '18 at 17:14
  • 2
    Qt is extremely good with forward declarations, so honestly, I wouldn't worry about being too stringent with "only" the absolutely needed headers. You have to read the code, and if you are picking up a project from another user, this will be fairly painstaking work to check what you can and cannot remove. Just remember some includes might be redundant due to what Qt currently includes (like `QString` including ``QByteArray`), but if you are using both, you may want to include both. The easiest way is to annotate your includes: say what classes or functions you need (Boost does this). – Alex Huszagh Oct 12 '18 at 17:17
  • For example, Boost authors, when writing code will annotate includes as follows: `#include // std::setw, std::setprecision`. When setw is removed, you remove it from the annotation, and if no more dependencies on the header exist, you may safely remove it. Painful, but possibly the easiest way to do so (to my knowledge). – Alex Huszagh Oct 12 '18 at 17:19
  • 2
    Then it's a shame. It seems one of those things that computers should be good at. – nuncaeslupus Oct 12 '18 at 17:19
  • @nuncaeslupus I think it's partially because a lot of standard headers have non-standard dependencies on other standard headers, which is entirely implementation dependent, meaning an automated way to remove them could work for 1 implementation and fail entirely for another. – Alex Huszagh Oct 12 '18 at 17:21
  • For example, the standard `` header only requires inclusion of ``, however, the Clang implementation also includes ``, ``, and other useful standard headers. `` and `` could then be found to be redundant, but MSVC's implementation of `` may not require them. In short, it seems easy, but may be a lot more difficult to implement than imagined.... – Alex Huszagh Oct 12 '18 at 17:23
  • 2
    [Include what you use](https://include-what-you-use.org) *tries*. But it *usually* fails horribly. – Jesper Juhl Oct 12 '18 at 17:27
  • I have watched that project on github for a long time but have not used it yet. I thought about suggesting it. – drescherjm Oct 12 '18 at 17:30
  • 1
    @AlexanderHuszagh Precisely the magic tool should tell you to include `` and ``, assuming you are using them in addition to a `deque`, to prevent errors if you change to another `deque` implementation. But if you have only included `` and you use `` but you don't use ``, it should tell you "delete `` and include just ``". – nuncaeslupus Oct 12 '18 at 17:39
  • It should, but it should also tell you not to include if you use and since deque guarantees to include the latter. It gets complicated quick. – Alex Huszagh Oct 12 '18 at 17:41
  • @JesperJuhl Interesting. I would settle for a Qt tool that analyzed Qt projects. – nuncaeslupus Oct 12 '18 at 17:45
  • 1
    @AlexanderHuszagh No, it should always tell you to include `` if you use it, even if `` already includes it. It should suggest you to include the more "specialized" headers for every symbol you use. – nuncaeslupus Oct 12 '18 at 17:52
  • 1
    @nuncaeslupus not exactly what you are after, but check out [Clazy](https://www.kdab.com/clazy-1-4-released/) and [ClangTidy](http://clang.llvm.org/extra/clang-tidy/). – Jesper Juhl Oct 12 '18 at 17:58
  • 1
    @JesperJuhl Thanks, I'll give them a try! – nuncaeslupus Oct 12 '18 at 18:02
  • 2
    A note on Qt headers: You should be including Qt headers named *exactly* for a class (`` not ``) , as that's whats documented as *guaranteed* to remain stable. Anything `.h` is subject to change between minor versions. – Caleth Oct 12 '18 at 19:26

1 Answers1

0

The rules of thumb to minimize the number of include files read:

  1. A .cpp file usually has an associated header. That header must be included first - it ensures that the header will compile by itself and is not missing any dependencies.

  2. For any class hierarchy, include only the most derived class's headers. E.g. if you include <QLabel>, you won't need <QFrame>, nor <QWidget>, nor <QObject>. If you include <QGraphicsView> and <QLabel>, you won't need <QAbstractScrollArea>, nor <QFrame>, nor <QWidget>, nor <QObject>. And so on.

  3. Other than in the preceding rule, do not depend on "files included by other files". I.e. QString including QByteArray is an implementation detail and the API of QString does not warrant such inclusion.

The rules of thumb to minimize the number of compiled source files:

  1. Cut the number of compiled files by two (!!) by adding #include "foo.moc" at the end of every foo.cpp that implements new QObject types.

  2. Short classes (<250 lines total) belong in a single .h file, there's no need to separate them between .h and .cpp.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313