views:

365

answers:

2

I've been looking at Boost and various other C++ libraries. The vast majority of Boost is implemented in header files.

My question is: under what conditions do you do a header-only implementation (like Boost) or also include a .cpp file?

+7  A: 

If you want to use a template in another translation unit (i.e. another source file), you should (almost always) define it in the header file. (There are exceptions, like the comments below point out, but IMHO this is a good rule of thumb.)

Same applies if you want to use an inline function from another translation unit.

Otherwise you should put the implementation into a separate .cpp file to minimize dependencies.

Péter Török
As for templates, it is not strictly true that you must put the (member) function definitions in the header file. You can put the definitions in a source file and use explicit template instantiation to make particular specializations available...
@STingRaySC Yeah, I had some vague memories from C++ Templates that it is possible, although I have never done it myself. However, I tried to give a rule of thumb which is good for starters and almost always applicable. Going into the special cases is for the experts (of which I am not one :-)
Péter Török
And you dont have to provide template implementations in the header file if your compiler supports `export`
smerlin
Complete specialisations of templates can go in source files.
Troubadour
Understood. I am a big proponent of explicit instantiation and will push it anytime I can. :) It is a heavily underutilized facility. The effect on compile and link time can be quite dramatic. Of course, it is only possible when you have a priori knowledge of what specializations are needed, and/or you have access to modify the source file where the explicit instantiations reside...
@smerlin: Unfortunately Comeau is the only compiler that supports `export`.
-1: Both statements are wrong. As pointed out by @STingRaySC it is not the case that templates "must" be defined in a header file. Similarly inline functions do not need to be in headers unless they are used in multiple translation units. It's perfectly possible (and sensible) to mark a function for inlining within a source file. Apparently there are now inlining linkers out there so even if the function is used in multiple translation units it may still be inlined if defined in the source file. I know what you're trying to say but I think the answer is too brief as it stands.
Troubadour
@Troubadour Good point, thanks. This is what I had in mind, just forgot to put it into words :-( Hope the updated version is clear enough.
Péter Török
@Troubadour: Though there are things like link-time code generation, and other link-time optimizations possible, I wouldn't assume this is so commonplace that I'd put functions I wanted to be candidates for inlining in a .cpp file. These capabilities require compiler/linker switches and in most cases are not on by default. Also, they may necessitate the exclusion of other common settings. Certainly, they wouldn't depend on a function being explicitly marked `inline`. As a best practice, I'd sill put inline-candidate function in a header file.
@Troubadour: ... Furthermore, if a class or function is declared in a header file, then it is almost certainly so that it can be used from multiple translation units.
@STingRaySC - No, Comeau is not the only compiler that supports export. Export was implemented by EDG (Edison Design Group), who sells compiler front ends to various vendors. The Green Hills Multi compiler (used in embedded systems) has the EDG front end and export is supported. But export is being removed entirely from C++0x.
Brian Neal
+3  A: 

Understanding this issue is basically about understanding how C++ compilation units work. Things in header files are basically pasted into the source code of a whole bunch of compilation units by #include statements. Each compilation unit gets compiled into an object file, the object files get linked, and you get conflicts because of that stuff being replicated all over the place.

The exceptions are things that (historically, at least) don't go into the object file because the compiler deals with them directly (e.g. inline functions), and things that can't be compiled in one unit then linked to another because they aren't completely defined (templates). Template functions often get identically instantiated in multiple compilation units, and the linker has special smarts to discard the duplicates.

This means that the separation of interface and implementation into header and body files isn't as very clean. Ada has a much cleaner separation - but a more complex build process to compensate IIRC. Java simply dropped the separate files for interface and implementation thing.

Linkers have got a lot more sophisticated over the years and taken over some of the work of the compiler, and a lot of this explanation is simply wrong these days, yet the basic patterns remain. Template functions and inline functions can (and often need to) go in the header, along with all your don't-directly-generate-object-code shared declarations. Normal function definitions should not be in a header file.

Steve314
Actually, linkers aren't that smart about `template` instanciations. They will basically take the first they encounter and rely on **ODR** (One Definition Rule). May lead to hard to find bug if only part of `Foo<int>` instanciations use a specialization!
Matthieu M.