C++ inline member function in .cpp file

C++FunctionInlineMember

C++ Problem Overview


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?

C++ Solutions


Solution 1 - C++

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.

Solution 2 - C++

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 own 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).

Solution 3 - C++

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.

Solution 4 - C++

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.

Solution 5 - C++

Here is the way I did it.

File A.h

#pragma once
#include "B.h"

class A {
    B b;
};

File B.h

#pragma once

class B {
public:
    template<class T> inline T getA() {
        assert(NULL); // Use 'getA<A>()' template specialization only!
        return NULL;
    }
};

class A; // Forward declaration
template<> inline A B::getA<A>();

File C.h

#pragma once
#include "A.h"
#include "B.h"

// Implement template specialization here!
template<> inline A B::getA<A>() { return A(); }

Just include the "C.h" file to be able to use getA() method. The only change with the original code is that the getA() method must be defined as public instead of private.

However, as many of you explained it, this is not really useful.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMatView Question on Stackoverflow
Solution 1 - C++ArunView Answer on Stackoverflow
Solution 2 - C++EboMikeView Answer on Stackoverflow
Solution 3 - C++SingleNegationEliminationView Answer on Stackoverflow
Solution 4 - C++Martin YorkView Answer on Stackoverflow
Solution 5 - C++Pascal ViguiéView Answer on Stackoverflow