views:

228

answers:

5

When writing a header library (like Boost), can one define free-floating (non-method) functions without (1) bloating the generated binary and (2) incurring "unused" warnings?

When I define a function in a header that's included by multiple source files which in turn is linked into the same binary, the linker complains about redefinitions. One way around this is to make the functions static, but this reproduces the code in each translation unit (BTW, can linkers safely dereplicate these?). Furthermore, this triggers compiler warnings about the function being unused.

I was trying to look for an example of a free-floating function in Boost, but I couldn't find one. Is the trick to contain everything in a class (or template)?

+8  A: 

You can use the inline keyword:

inline void wont_give_linker_errors(void)
{
    // ...
}
GMan
+9  A: 

If you really want to define the function (as opposed to declaring it), you'll need to use inline to prevent linker errors.

Otherwise, you can declare the function in the header file and provide its implementation separately in your source file.

David Joyner
Of course, using "inline" increases the chances that the function be inlined, which can result in code bloat in the application using that header.
Vladimir Prus
+1  A: 

Besides the already mentioned inline, with most compilers templates have to be defined in headers (and with all compilers it's allowed). Since boost is mostly templates, that explains why it is almost all headers.

sbi
A: 

People have suggested inline but that violates the very first part of your question i.e. it bloats the code as the full definition is inserted into the code at each call of the function. The answer to your overall question is therefore "No".

If you mark them as static then they are still defined in each source file as you rightly pointed out but only once and so that's a better option than inline if code size is the only issue. I don't know if linkers can, or are allowed to, spot the duplicates and merge them. I suspect not.

Edit:

Just to clear up any confusion as to whether I support the notion of using static and/or defining functions within headers files generally then rest assured I don't. This was simply meant as a technical response as to the differences between functions marked inline and static defined in header files. Nothing more.

Troubadour
`inline` has two roles: first, prevent multiple definitions to be an error. Second, it's a **hint** to the compiler that this function can be inlined. In practice, compilers don't inline large functions (unless e.g. it's the only occurence).
peterchen
Isn't it the other way round? Aren't those precisely static functions that would trigger the "unused" warnings? (Doesn't static mean that each including file gets its own version of the function, and since it is "custom-made", it would indeed be nice if they all used it somewhere?)
UncleBens
@peterchen: I know it's a hint so I'm describing a worst-case scenario, something I didn't make clear.
Troubadour
@UncleBens: I'm not sure who you're asking the question to? Using `static` may well give unused warnings, certainly the OP said it did for him. I certainly haven't said anything to contradict that.
Troubadour
@Troubadour: I meant, you talked about requirement 1), but suggested something that is pretty much guaranteed to fail requirement 2). Also, wouldn't static mean the same function will be generated multiple times, making the exe larger? Also, what makes you think the compiler cannot choose to inline (or not) the static function, as long as it sees the implementation? (As far as I see, the purpose of `inline` is so that you can define functions in headers, without which the compiler has no option but not to inline.)
UncleBens
@UncleBens: This is unbelievable. Are you reading anything? I said that the answer to the overall question was "No" i.e. both requirements can't be fulfilled. When discussing the technical difference between `inline` and `static` I say clearly "if code size is the _only_ issue". Please note the emphasis on the word "only". As for your second point the same function is generated multiple times, once for each object whose source included the header. That's what I said. An inline function's definition _may_ appear multiple times within the same object. Think about it.
Troubadour
@Troubadour: What you are missing is that the only thing the compiler needs to inline a function call is to have the full definition of the function (the *linker* can inline other function calls). The compiler can and will inline static functions as well, as long as it passes the heuristics for the given optimization settings and the function body is available (defined in the header).
UncleBens
+3  A: 

Er... The answer to your question is simply don't. You just don't define functions in header files, unless they are inline.

'static' function can also be defined in headers, but it is only useful for very specific rare purposes. Using 'static' just to work around a multiple-definition problem is utter nonsense.

Again, header files are for non-defining function declarations. Why on Earth would you want to define functions there?

You said you are writing "header library". What's a "header library"? Please note, that Boost defines its "functions" in header files because their "functions" are not really functions, they are function templates. Function templates have to be defined in header files (well, almost). If that's wasn't the case, Boost wouldn't be doing something as strange as defining anything in header files.

AndreyT
Er...., templates. :) Excellent point nonetheless. I addressed the technical nature of using `static` in my answer but not the correctness of it.
Troubadour
If the OP was defining templates, he woudn't have the multiple definition problems in the first place. Also, there's a terminological distinction here that I'm always trying to observe: *function template* is not a *function*.
AndreyT
Yes I know he wouldn't have that problem if he were using templates. What's that got to do with the price of bread? I suppose I'll have to take your word for it that you were using "function" to refer to non-template functions, obviously your edit appeared after my comment. Sorry for upvoting you.
Troubadour
Well, maybe I misunderstood your comment somehow (I still don't understant what offended you.) But even though my edit appeared after yor comment, I saw your comment only after I submitted my edit (i.e. you submitted your comment wile I was busy making the edit). For that, of course, you can only take my word.
AndreyT