C++ header-only include pattern

1.8k views Asked by At

I would like to write code in .hpp without separation to .h and .cpp

  • I did it. I use .cpp only for static class-fields definitions

I would like not to write #include manually ...

  • I use forward delarations where it possible.
  • Every my .hpp file containt #pragma once.
  • But, when my project grows up to 40-50 classes i saw problem of include graph. There are some errors of definitions.

Image with include graph of my project model (like part of mvc) attached.
I used this app for graph generation (can work without MSVS!).

include graph

How include graph should look like? Like a tree?
How not to write includes manually, like in C# or Java?

4

There are 4 answers

3
Mark B On BEST ANSWER

Unfortunately you're possibly using the wrong language. There are some things that are just much in C++ easier when you separate the class definition from implementation. Even with forward declarations you'll probably still wind up with circular dependencies that can only be resolved by moving implementations into separate files.

If you want to write idiomatic Java, just write it in Java. If you want to use the C++ language unfortunately you'll have to work within its constraints.

0
Thomas Matthews On

I highly suggest placing implementation into ".cpp" files and declarations or interface into header files, ".hpp".

When an inline function is changed in a header file, ALL source files that include the header file will be recompiled. When a function is changed in a source file, only the source file needs to be recompiled.

Get the code working correctly and robustly before creating inline functions.

Another suggestion is to make libraries (collection of object files) for source files that are grouped by a theme or are not compiled often (i.e. they work and don't change).

Don't worry about the quantity of files nor the length of the build process. Focus on completing the project correctly, robustly and under schedule. Adjust the build process as necessary. If there is a lot of time in the schedule are the code works correctly and is robust, then make changes. If changing the build process can speed up development time *significantly", then make the changes.

2
Daniele Pallastrelli On

Let's assume you have a .hpp file per class, then, the include graph is similar to the class dependency graph. For sake of reusability, a class dependency graph should be acyclic (you can achieve this by using interfaces to "split" cycles). So, I guess the include graph should be acyclic too.

As for the #include clauses, I'm afraid you have to write them manually. But if your classes are small enough, this shouldn't be a problem (if your classes are so huge you can't figure out what include you need, you've got a design problem).

1
M. Williams On

Just as a small note, splitting your classes into .cpp and .h files not only solves the circular dependency problem, but also might dramatically increase your compilation time.

If you're attempting to write header-only code, you would probably end up with a full rebuild of your project even if one small part of code gets changed.

Header-only code only makes sense if you're designing a template-based library, basically, because template should reside in headers. See boost template library, for example. And also to mention, real application using template libraries still have those .cpp files for their code and that's where the instantiated templates are actually "used".