views:

75

answers:

4

I know that inline member functions by definition should go into the header. But what if it's not possible to put the implementation of the function into the header? Let's take this situation:

File A.h

#pragma once
#include "B.h"

class A{
    B b;
};

File B.h

#pragma once

class A; //forward declaration

class B{
    inline A getA();
};

Due to the circular include I have to put the implementation of getA into

B.cpp

#include "B.h"
#include "A.h"

inline A B::getA(){
    return A();
}

Will the compiler inline getA? If so, which inline keyword is the significant one (the one in the header or the one in the .cpp file)? Is there another way to put the definition of an inline member function into its .cpp file?

+3  A: 

It can't, outside the scope of B.cpp. The compiler operates on a per-compile-unit base, i.e. it compiles each .cpp file individually, so if it compiles C.cpp, it won't have the code for getA() available and will need to perform a function call and have the linker fix it up (or, if it really took you by the word and tried to inline, it will have end up with a linker error. inline has similar qualities as static).

The only exception is LTCG, i.e. link-time code generation, which is available on newer compilers.

One approach in this case is to have another header file (sometimes named *.inl files) that contain the inlined code.

EDIT: As for which inline is relevant - it's the one in the class definition, i.e. in the header file. Keep in mind that many compilers have their on mind on what can and should be inlined. gcc for example can disable inlining completely (-O0), or it can inline anything that it deems worth inlining (like -O3).

EboMike
so - in my example - i'd simply rename B.cpp to B.inl and everyhwere where i usually would include B.h i'd instead include B.inl?
Mat
I wouldn't rename B.cpp to B.inl - I would create a separate B.inl (or preferably B_inline.h) and put all inlined functions in there. Then, in your B.cpp, include the _inline.h file.
EboMike
+5  A: 

Quoting from C++ FAQ:

Note: It's imperative that the function's definition (the part between the {...}) be placed in a header file, unless the function is used only in a single .cpp file. In particular, if you put the inline function's definition into a .cpp file and you call it from some other .cpp file, you'll get an "unresolved external" error from the linker.

The compiler need to see the definition of the inline function whenever it finds any use of that inline function. That is typically possible if the inline function is placed in a header file.

Will the compiler inline getA?

No, except when the the use of getA() is in B.cpp itself.

If so, which inline keyword is the significant one (the one in the header or the one in the cpp)?

Best practice: only in the definition outside the class body.

Is there another way to put the definition of an inline member function into it's cpp file?

No, at least I don't know.

ArunSaha
+2  A: 

These days, most compilers can perform inlining at link time, as well as compile time. If your function is likely to benefit from inlining, then the Link Time optimizer is likely to do just that.

By the time the linker gets to it, not much about the inline status of compiler output is available, except that the compiler will flag certain objects as being collectible, for instance because an inline function or class template instance appears in multiple compilation units, or it should raise an error when multiple symbols share a name, such as the main function being defined twice. None of this has influence on the actual code it will generate.

TokenMacGuy
I didn't know that's possible. does the linker care about the "inline" keyword or it just decides itself what to inline?
Mat
I wouldn't be so sure about the "most" part. Also, LTCG is horribly slow, and personally I like having more control over what the compiler does.
EboMike
@EboMike: The control you think you have is an illusion. The compiler will always be better than you at deciding what is worth inlining. (Humans are horrible at doing the analysis required). Let the compiler do the job it was meant to do (inlining) let the human do what it is good at (thinking about algorithms).
Martin York
@Mat: All modern compilers ignore the inline keyword (in relation to inline-ing code) (Unless you force them too with a compiler flag and that is always a mistake (unless you really know what you are doing and if you think you do then you don't)). The linker does need the inline keyword to know that it should ignore multiple definitions (or consolidate multiple definitions of a function) otherwise it must assume you have screwed up and generate an error.
Martin York
+1  A: 

I would go about this from the opposite direction.

Don't add inline declarations to your function (unless you need too).

The only time you need to add the inline declaration to a function/method is if you define the function in a header file but outside the class declaration.

X.h

class X
{
    public:
        int getX()   { return 4;} // No inline because it is part of the class.
                                  // The compiler knows that needs an inline tag
        int getY();
        int getZ();
};

inline
int X::getY()  { return 5;}       // This needs to be explicitly declared inline.
                                  // Otherwise the linker will complain about
                                  // multiple definitions in compilation units.

X.cpp

 // Never declare anything inline in the cpp file.

 int X::getZ() { return 6; }

To you more specific case.
Remove all the inline specifications. They are not doing what you think they are doing.

Martin York
ah - so if a function is defined within the body of a class, then it will be inlined anyway?
Mat
@Mat: It will be tagged as if had the inline keyword applied. Do not confuse this with the compiler inlining code. All modern compilers completely ignore the tag (for the pedantic: the linker does use it (but not for inlining)).
Martin York