views:

107

answers:

2

I have a namespace with inline function that will be used if several source files. When trying to link my application, the inline function are reported as duplicate symbols. It seems as if my code would simply not inline the functions and I was wondering if this is the expected behavior and how to best deal with it.

I use the following gcc options: -g -Wextra -pedantic -Wmissing-field-initializers -Wredundant-decls -Wfloat-equal -Wno-reorder -Wno-long-long The same code style seems to compile and link properly when build in a VC7 environment.

The following code example shows the structure of the code:

/* header.h */
namespace myNamespace {
inline bool myFunction() {return true;}
}

/* use_1.cpp */
#include "header.h"
...
bool OK = myNamespace::myFunction();
...

/* use_2.cpp */
#include "header.h"
...
bool OK = myNamespace::myFunction();
...
+1  A: 

Keep in mind that inline is just a hint, a request if you will. The compiler is well within it's bounds to ignore your request if it sees fit.

It might do this because of optimization settings, or other reasons.

You might ask yourself if you really need these functions to be inline. This is a common premature micro-optimization, perpetuated by some texts advising that small & frequently-called functions could be inlined to improve performance. Unless there's a performance problem, your just adding complexity by inlining these functions.

If you move the implementation of the functions to a CPP file, inline directive intact, you may have better luck. The compiler may ignore your inline request as it seems to be doing now, but you should compile just fine. You might also be able to make your functions template functions, thereby asking the compiler to inlinethem again, which again it may ignore.

EDIT: From the comments below, I think it's a good idea to clarify what "inline is just a hint" means.

From the Standard:

7.1.2 Function Specifiers

2: A function declaration (8.3.5, 9.3, 11.4) with an inline specifier declares an inline function. The inline specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. An implementation is not required to perform this inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules for inline functions defined by 7.1.2 shall still be respected.

So, when you put the declaration and the definition of a function in a header file with the inline keyword, like this:

namespace myNamespace {
inline bool myFunction() {return true;}
}

...there are a couple of spinning plates. First, in order for the program to be well-formed, the inline keyword needs to be respected by the compiler, otherwise you will violate the one-definition rule. But second, there is still no requirement by the implementation to honor your inline request. If it does, you're golden. If it doesn't, you're screwed. In effect, the well-formedness of your program depends on the compiler respecting your inline request.

I have re-read the Standard with respect to inline and found nothing that indicates that a compiler must respect inline for certain cases. If anybody knows of a clause that makes my claim incorrect, please share it!

John Dibling
Actually, your comment is dangerously wrong. The inline keyword in this context is much needed or the definition in the header file would cause duplicate symbols.
Gabriel Schreiber
I agree with @Gabriel Schreiber. `inline` is *not* just a hint; it is _required_ with the code as it stands because defining the function in a header files means that there is more than one definition of the function in the program. `inline` allows the needed exception to the one definition rule.
Charles Bailey
@Gabriel: You mean duplicate symbols like OP is encountering? Point being my statement that `inline` is not something the compiler is required to conform to is not wrong.
John Dibling
@Charles: It is required for the programmer to add it in order for the code to be compliant. The compiler may still ignore it however, and in fact seems to be doing exactly that.
John Dibling
In terms of inlining, `inline` is a hint. But it actually makes a semantic difference with respect to the one-definition-rule. Here, inline is needed to avoid multiplt definition linker errors for the function if the header is included into multiple translation units.
sellibitze
@John Dibling: No, the compiler (including linker, because that's relevant here) _must_ conform to the requirements of `inline`. In particular it must not fail to compile for the sole reason that there are multiple definitions of an `inline` function in a program. Of course, if the program doesn't conform (e.g. the definitions aren't identical or there isn't one in a TU that uses the function) then the compiler may fail in any way.
Charles Bailey
John Dibling
@John Dibling: I don't understand. I don't intend to counter 7.1.2/2?
Charles Bailey
@John: There is a misunderstanding. When you say "the compiler might igore it" then you're talking about the "act of inlining". That's not what *we* are talking about. The `inline` keyword actually changes the semantics of your program. Just check the one definition rule. Whether the compiler actually inlines a function or not does not matter one bit in terms of linker errors -- at least in C++. Maybe you're just not familiar with the semantics of inline in C++? There's actually a difference between C and C++ here.
sellibitze
@All: Please read my edit
John Dibling
@All: I have to go for now, but I will be checking this thread later. I'll re-read it and make sure I didn't misunderstand something
John Dibling
As far as I can see, you've just posted in support of my argument: "however, even if this inline substitution is omitted, the other rules for inline functions defined by 7.1.2 shall still be respected." This means that `inline` cannot be ignored even if the compiler doesn't perform the inline substitution. I'm not sure if this is because you've changed your position or you meant something different originally.
Charles Bailey
Frankly, I think the answer is still confusing. It's confusing because depending on how you define "the compiler honors/respects inline" it is either true or false. It is true if you're talking about the compiler respecting the one definition rule with all its exceptions. It's false if you're talking about the compiler inlineing a function (in general). Don't get hung up on the inlining part. The one definition rule is what matters. Anything else is up to the compiler. It can do whatever it wants under the as-if rule.
sellibitze
Thank you for all the helpful feedback. There is a lot of information but was seems to be key for this issue is that despite the fact if the compiler does actually inline the methods they should NEVER cause a duplicate. Forcing the compiler to inline the function might be an option to get around my problem but should actually not be needed. If I got it wrong: tell me please! The example code is taken from a larger project and I will now create a proper example and slice down my code to see what other reasons might cause my problem.
materialdreams
A: 

The inline keyword is taken only as a hint by the compiler. If the compiler decides that the function would be better performing without inline, it will not inline it. There are vendor-specific keywords that make the compiler inline a function - it is __attribute__((always_inline)) for GCC and __forceinline for Visual C++.

If you really want to make sure your function won't be causing linker errors in all cases on all standard compilers, you might want to make it templated, as templated functions are guaranteed not to cause linker errors even if defined in headers. This is, however, quite unnecessary for really simple functions.

dark_charlie
Your code doesn't cause linker errors if you write it properly. Writing templates where they are not needed is nonsense.
Gabriel Schreiber
Whether a C++ compiler inlines a function or not is not important here. The compiler handles this transparently under the as-if rule. Nevertheless `inline` affects the program's semantics. It is appropriate here regardless of whether the compiler actually inlines the function. Please research the "one definition rule".
sellibitze
SOLVED: I finally had the time to track down the problem to it's roots and (as so often) it was a simple consistency problem with the use of precompiled headers. I learned that the use of inline is in fact transparent and does not require to take care if the compiler actually does inline the function or not. And most important: always use the -Winvalid-pch flag when using precompiled headers.
materialdreams