84

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?

SCFrench
  • 8,244
  • 2
  • 31
  • 61
Mat
  • 2,713
  • 5
  • 25
  • 25
  • Are you under the mistaken impression and think that the keyword inline means that the compiler generate inline assembly instead of making a function call? – Martin York Oct 22 '10 at 00:45
  • nah - i'm aware what should happen – Mat Oct 22 '10 at 01:07
  • Are you sure. What do you think should happen? – Martin York Oct 22 '10 at 01:09
  • i think the compiler should place the actual code of the function into any caller function - similar to a macro. – Mat Oct 22 '10 at 03:42
  • 3
    @Mat. No. It means nothing in terms of inlineing code. It is merely a hint (that all modern compilers ignored). There is no requirement for the compiler to do anything. The compiler analysis all functions for potential inlining whether or not the keyword 'inline' is used. – Martin York Oct 22 '10 at 05:31
  • 4
    yeah i know that it's just a hint - anyway you say the keyword "inline" got obsolete? – Mat Oct 22 '10 at 13:28

5 Answers5

81

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.

Arun
  • 19,750
  • 10
  • 51
  • 60
  • Many people introduce a third file, extension *.inl*, to place inline functions definitions. This file is included at the end of the header file. – Sandburg May 17 '23 at 13:26
24

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

EboMike
  • 76,846
  • 14
  • 164
  • 167
  • 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 Oct 22 '10 at 00:27
  • 1
    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 Oct 22 '10 at 00:34
  • 1
    *"It can't, outside the scope of B.cpp..."* - Some of the reasons for the NO may have changed now that some toolchains have link time optimizations (LTO). It can be enabled `-flto` when using GCC and some other compilers. – jww Nov 16 '17 at 06:55
  • @jww Not sure if you read to the second paragraph, but that's where I mentioned LTCG/LTO :) Which is of course more common now than back in 2010 when I wrote this. Although personally I still like to write C++ code that helps the compiler optimize by putting inlineable functions into header files. – EboMike Nov 16 '17 at 16:40
10

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.

Community
  • 1
  • 1
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • 1
    ah - so if a function is defined within the body of a class, then it will be inlined anyway? – Mat Oct 22 '10 at 13:26
  • 1
    @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 Oct 22 '10 at 16:37
  • Thank you, you saved my day. I was looking for a solution form my 1000s of LNK4006 warnings. Now gone! – Dmitry Babich Apr 29 '23 at 05:24
8

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.

SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304
  • I didn't know that's possible. does the linker care about the "inline" keyword or it just decides itself what to inline? – Mat Oct 22 '10 at 00:29
  • 2
    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 Oct 22 '10 at 00:33
  • 1
    @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 Oct 22 '10 at 01:06
  • 1
    @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 Oct 22 '10 at 01:08
0

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.