Is it ever impossible to write a header-only library?
Asked Answered
T

4

15

Is there ever such a pattern of dependancies that it is impossible to keep everything in header files only? What if we enforced a rule of one class per header only?

For the purposes of this question, let's ignore static things :)

Trocar answered 20/9, 2010 at 17:13 Comment(7)
What if headerless library A depends on DLL-only library B? Or is that ruled out by the last sentence? Of course you could always reimplement it as headers, so maybe not impossible.Kangaroo
do you have to talk to other languages?Dorton
@Skurmedel: C++ defines no DLL-like facility, so anything there is going to be implementation specified. I doubt it makes any difference though.Oliviero
Please read the question carefully before you answer. Don't quick-fire answer "can I write header-only stuff?", that's not the question. The question is "is there any code that would require a translation unit, and therefore cannot be strictly header-only?"Haubergeon
A problem are things that must be defined only once, but cannot be inlined such as static data members or global objects. I know a way around the static member problem (put these into a class template), but haven never given thought to global data. Also, I'm not sure about explicit template instantiations. Are those subject to the ODR?Finder
@sbi: Seeing how you can simply use static members instead of globals, it wouldn't make it impossible anyway. And are explicit template instantiations unavoidable in any case?Fye
@Georg: I was thinking of something like std::cout. To make that a class template's static data member would make for some really ugly syntax when using it. And template instantiations might be avoidable, but specializations are not, and when you fully specialize, wouldn't that fall under the ODR? Of course, you could fallback on partial specialization for that, but, again, that might make it harder to use this (not to speak of the increased complexity).Finder
O
7

I am aware of no features in standard C++, excepting statics which you have already mentioned, which require a library to define a full translation unit (instead of only headers). However, it's not recommended to do that, because when you do, you force all your clients to recompile their entire codebase whenever your library changes. If you're using source files or a static library or a dynamic library form of distribution, your library can be changed/updated/modified without forcing everyone to recompile.

Oliviero answered 20/9, 2010 at 17:28 Comment(3)
"you force all your clients to recompile their entire codebase whenever your library changes" - even worse, in practice, you force them to recompile your library whenever their codebase changes.Schilt
Though it does make the library trivial to use, and helps the compiler when it optimizes.Haubergeon
@GMan: Depends on the compiler. IIRC, both GCC and MSVC have link time code generation facilities now for release builds, which removes most (if not all) potential performance differences.Oliviero
U
6

It is possible, I would say, at the express condition of not using a number of language features: as you noticed, a few uses of the static keyword.

It may require a few trick, but they can be reviewed.

  1. You'll need to keep the header / source distinction whenever you need to break a dependency cycle, even though the two files will be header files in practice.
  2. Free-functions (non-template) have to be declared inline, the compiler may not inline them, but if they are declared so it won't complained that they have been redefined when the client builts its library / executable.
  3. Globally shared data (global variables and class static attributes) should be emulated using local static attribute in functions / class methods. In practice it matters little as far as the caller is concerned (just adds ()). Note that in C++0x this becomes the favored way because it's guaranteed to be thread-safe while still protecting from the initialization order fiasco, until then... it's not thread-safe ;)

Respecting those 3 points, I believe you would be able to write a fully-fledged header-only library (anyone sees something else I missed ?)

A number of Boost Libraries have used similar tricks to be header-only even though their code was not completely template. For example Asio does very consciously and proposes the alternative using flags (see release notes for Asio 1.4.6):

  • clients who only need a couple features need not worry about building / linking, they just grab what they need
  • clients who rely on it a bit more or want to cut down on compilation time are offered the ability to build their own Asio library (with their own sets of flags) and then include "lightweight" headers

This way (at the price of some more effort on the part of the library devs) the clients get their cake and eat it too. It's a pretty nice solution I think.

Note: I am wondering whether static functions could be inlined, I prefer to use anonymous namespaces myself so never really looked into it...

Unfounded answered 20/9, 2010 at 19:24 Comment(1)
re #1: Can you sketch a scenario where this would be necessary? I tried to imagine one, but couldn't come up with anything that can't be solved by moving inlined function definitions behind all the necessary definitions.Finder
B
2

The one class per header rule is meaningless. If this doesn't work:

#include <header1>
#include <header2>

then some variation of this will:

#include <header1a>
#include <header2>
#include <header1b>

This might result in less than one class per header, but you can always use (void*) and casts and inline functions (in which case the 'inline' will likely be duly ignored by the compiler). So the question, seems to me, can be reduced to:

class A
{
// ...
void *pimpl;
}

Is it possible that the private implementation, pimpl, depends on the declaration of A? If so then pimpl.cpp (as a header) must both precede and follow A.h. But Since you can always, once again, use (void*) and casts and inline functions in preceding headers, it can be done.

Of course, I could be wrong. In either case: Ick.

Behah answered 20/9, 2010 at 17:59 Comment(2)
I don't see why anyone would use any kind of pimpl class in a header only library, given that the idea if the pimpl idiom is to break things into separate translation units...Oliviero
I agree, there's no point in trying to making a header only library when the implementation is clearly unsuited to it. Maybe that's not what you meant ;) I brought up pimpl as a tool to prove it could be done (using the word 'prove' very loosely).Behah
F
1

In my long career, I haven't come across dependency pattern that would disallow header-only implementation.

Mind you that if you have circular dependencies between classes, you may need to resort to either abstract interface - concrete implementation paradigm, or use templates (using templates allows you to forward-reference properties/methods of template parameters, which are resolved later during instantiation).

This does not mean that you SHOULD always aim for header-only libraries. Good as they are, they should be reserved to template and inline code. They SHOULD NOT include substantial complex calculations.

Franchescafranchise answered 8/9, 2014 at 19:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.