views:

94

answers:

5

I want to write a library that to use, you only need to include one header file. However, if you have multiple source files and include the header in both, you'll get multiple definition errors, because the library is both declared and defined in the header. I have seen header-only libraries, in Boost I think. How did they do that?

+10  A: 

Declare your functions inline, and put them in a namespace so you don't collide:

namespace fancy_schmancy
{
  inline void my_fn()
  {
    // magic happens
  }
};
John Dibling
But, is it recommended to make **all** functions `inline` irrespective of their nature? I thought only "short" functions should be `inline`'d.
ArunSaha
Ignore your professors. They don't write code for a living. "Only short functions should be inlined" is a rule of thumb, but there are so many exceptions and so many other more important reasons why you should or should *not* inline a function so as to make the rule of thumb almost useless.
John Dibling
"Premature micro-optimization is the root of all evil" being the first reason not to inline that comes to mind.
John Dibling
@Arun: The compiler isn't required to inline all `inline` functions, and it can't in the case you call through a function pointer. The `inline` keyword is a hint that inlining might be nice, but more importantly it's a linkage modifier. It's an unfortunate misnomer. Anyway, don't worry about your compiler doing anything stupid.
Potatoswatter
@John Dibing, @Potatoswatter: Thanks. May be I am missing something, but these comments sound like one could/should make whole project with `inline` functions. What is a good guideline to follow? Any link or book-chapter reference is appreciated.
ArunSaha
+1  A: 

Boost uses header-only libraries a lot because like the STL, it's mostly built using class and function templates, which are almost always header-only.

If you are not writing templates I would avoid including code in your header files - it's more trouble than it's worth. Make this a plain old static library.

Steve Townsend
A: 

There are many truly header-only Boost libraries, but they tend to be very simple (and/or only templates). The bigger libraries accomplish the same effect through some trickery: they have "automatic linking" (you'll see this term used here). They essentially have a bunch of preprocessor directives in the headers that figure out the appropriate lib file for your platform and use a #pragma to instruct the linker to link it in. So you don't have to explicitly link it, but it is still being linked.

rmeador
How do you use the automatic linking thing in g++? I know in MSVC++ you can use `#pragma(lib, "blah.lib")` but how do you do the same with g++?
Epro
@Epro: I'm afraid I don't know how it's done. You might have to look at the Boost source.
rmeador
A: 

The main reason why Boost is largely header-only is because it's heavily template oriented. Templates generally get a pass from the one definition rule. In fact to effectively use templates, you must have the definition visible in any translation unit that uses the template.

Another way around the one definition rule (ODR) is to use inline functions. Actually, getting a free-pass from the ODR is what inline really does - the fact that it might inline the function is really more of an optional side-effect.

A final option (but probably not as good) is to make your functions static. This may lead to code bloat if the linker isn't able to figure out that all those function instances are really the same. But I mention it for completeness. Note that compilers will often inline static functions even if they aren't marked as inline.

Michael Burr
Well, the Boost docs cites the header-only nature of much of the library as a feature. And it's only the stuff that can't reasonably be header only (e.g. the regexp stuff has OS dependencies) that isn't header only. So while some sub-libraries undoubtedly are header only because they're template code, it's wrong to ascribe that reason to Boost as a whole, at least according to the docs.
Alf P. Steinbach
A: 

Header-only libraries are used for class templates and function templates, where a specific class or function is created based on their usage. (Detailed information)

If you have to write here is a simple trick. Of course, it uses templates :-)

// Header file: foo.hh
template< bool dummy = true >
class Foo {
    // useful things here
};

An otherwise-nontemplate class is deliberately templatized using a (dummy) template argument of type bool which defaults to true. To use this, all user code has to type two extra characters. Instead of usual

Foo foo;

they have to write it as following

// Any source file: bar.cpp
#include "foo.hh"
Foo<> foo;

Following two variations would also work

Foo< true > foo;   // Same as Foo<> foo;
Foo< false > foo;  // Since the bool argument is just a dummy
ArunSaha
Why even do that? There's no need.
GMan
@GMan: Thanks for looking at the answer and posting your comment. What specifically you meant by "that"? In general, the implementation of `Foo` goes to `foo.cpp` and other source files links with that. However, here the question was to how to avoid `foo.cpp` and yet not get multiple definition error from other user files, e.g. `bar.cpp`, `bar1.cpp`, and so on? When you say, "There's no need", which specific part you refer to? Or, is it the whole answer? :-)
ArunSaha
The answer with the check mark gives an easier way.
Epro
@Arun: I mean why make it an artificial template? It changes the classes unnecessarily, when other solutions exist.
GMan
**@GMan:** I agree that it is artificial template, but the requirement is also artificial isn't it? Also, doesn't the other solution artificially `inline` **all** functions? Is there any solution without doing anything artificial? [BTW, I learnt this artificial template solution by reading some standard library code :-)] **@Epro:** The other solution is fine, but it requires all functions to be `inline`d.
ArunSaha
Which is better than having to make it a template.
Epro
@Epro: What's so wrong with templates? The standard library is standing on the shoulder of templates.
ArunSaha
@Arun: They're templates because it makes *sense* for them to be. This class has absolutely no business being a template class. You seem to think making them inline has a cost. It has no cost, and makes more sense.
GMan
@GMan, @Epro: Thanks for your time and comments. Looks like I have to read/experiment more on `inline` :)
ArunSaha