Search code examples
c++inline

Inline functions across multiple C++ translation units


I recently learnt about inline functions in C++. I understand how they work (in terms of expanding the code instead of making jumps etc), however I'm a little confused regarding how I should use them when it comes to multiple translation units / *.cpp files.

I've read that, as a rule of thumb, I should contain the definition of the function itself inside a header file (and not just its declaration) and then include the header file in each translation unit I aim to use said inline function. That is not a problem for an inline function, since it will just exist standalone on each translation and expand itself when/if needed (decided by the compiler) [ please correct me if I am wrong regarding any of this!]

However, I also read that during link time, even if the definition of an inline function itself is not present in the header file, the linker can find its definition and expand it if needed. But how would the linker be able to expand a function from a different translation unit? And if that's the case, why would I need to include the definition of the function in each translation unit (through header files)?


Solution

  • The inline keyword in front of a function was only an optional indicator for the compiler that inline is preferred. Modern compilers don't care about the inline keyword when it comes to code inlining.

    The important meaning about inline is "multiple definitions are permitted", member functions definitions implicitly inline if they are in the body of the class.

    You need inline if you have the same function definition in multiple translation units (e.g. if you place the function definition in a header, and that header is included by multiple cpp files)

    I've read that, as a rule of thumb, I should contain the definition of the function itself inside a header file (and not just its declaration) and then include the header file in each translation unit I aim to use said inline function. That is not a problem for an inline function, since it will just exist standalone on each translation and expand itself when/if needed (decided by the compiler)

    Placing a function definition in the header makes it easier for the toolchain to do inlining because it knows its definition when it is used and can perform the inlining in the compilation step. Having a function definition in multiple translation units requires it to be marked with inline.

    However, I also read that during link time, even if the definition of an inline function itself is not present in the header file, the linker can find its definition and expand it if needed. But how would the linker be able to expand a function from a different translation unit?

    A toolchain could do link-time optimization (like inlining) for any function (no matter if their definition is known at compile time) for which the definition is known at linking time (static linking), but link-time optimizations tend to - at least in the past - not as efficient as compile-time optimizations.

    The problem with link-time optimizations is, that toolchain either needs to keep track of the additional information provided by the source code that is helpful for optimizations or needs to rely on possible less powerful the strategies you can apply on the binaries.

    If you have a main.cpp that looks like this:

    int sum(int a, int b) {
      return a+b;
    }
    
    int main() {
      std::cout << sum(3,4) << std::endl;
      return 0;
    }
    
    

    Any modern compiler will inline that code (or in that case event completely optimize it aways to std::cout << 7 << std::endl;).

    Also this will be fine and inlined/optimized:

    sum.h

    int sum(int a, int b) { // no inline keyword in front of the function
      return a+b;
    }
    

    main.cpp

    #include "sum.h"
    int main() {
      std::cout << sum(3,4) << std::endl;
      return 0;
    }
    
    

    But as soon as you use #include "sum.h" in multiple cpp files and link those translation units together you get a problem and need to use inline. inline in front of a function is nowadays really only there to tell the linker that having the same definition in multiple translations units is your intent.