90

I believed, inline was obsolete because I read here:

No matter how you designate a function as inline, it is a request that the compiler is allowed to ignore: the compiler might inline-expand some, all, or none of the places where you call a function designated as inline.

However, Angew seems to understand something I don't. In this question he and I go back and forth quite a bit, on whether inline is still useful.

This question is not a question on:

Bearing in mind that the compiler can inline at will, so inline is not helpful there: Where can inline be used to force, not suggest, a change in compiled code?

Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • 1
    @MatthieuM. I looked at: http://stackoverflow.com/questions/1759300/when-should-i-write-the-keyword-inline-for-a-function-method before posting, I felt that this was a question about `inline`'s effect on inlining code. I specifically state that I did *not* want to know about that. I wanted to know about `inline`s alternate use. In my mind these two questions are very different. – Jonathan Mee Apr 22 '15 at 18:19
  • 2
    Well, personally I found that your question was a duplicate; since once you establish that `inline` is useless to hint about inlining, then only the semantics remain and that is exactly what "When should I write the keyword 'inline' for a function/method?" was about. But since your question was reopened apparently others thought the same. Note that if you looked at other questions, it is recommended that you link it and explain why you think your question is different. – Matthieu M. Apr 23 '15 at 08:52
  • 4
    I downvoted because of the serious mismatch between the question title and the actual question. You ask, "is there still a use for inline?", to which the answer is "yes, because of the ODR", and you also ask, "where can `inline` be used to force a change in compiled code?", to which the answer is "nowhere, unless you get into some specialized compiler options". Then you say actually you knew the first thing all along and the real question is the second thing. – Steve Jessop Apr 23 '15 at 08:55
  • @MatthieuM. I have added a section on some of the questions that I looked at along with how I feel this question differs. I appreciate your constructive criticism, I hope that it has made for a better question in the end. – Jonathan Mee Apr 23 '15 at 11:24
  • @SteveJessop I believe that the answers bellow adequately spell out how `inline` *can* be used to force a change in compiled code; in that the code could not compile without `inline` because of the ODR. I pondered over how I could increase the precision on that question, but in the end it seemed the best I could do already. I would welcome a suggestion if you feel there is something that could be said which would appropriately differentiate the question. – Jonathan Mee Apr 23 '15 at 11:32
  • 2
    @JonathanMee: OK, well if "yes, because of the ODR" is an acceptable answer, then it's a dupe of the question you linked to, since the answer to that is "whenever required by the ODR". A tiny variation in the way of asking a question that's been gone over before doesn't make a new question, and if what you're trying to ask is, "do we still need to use inline for the reasons given in that answer from 2009, to do with the ODR?", then again, "is this still true?" is IMO a dupe. – Steve Jessop Apr 23 '15 at 12:22

2 Answers2

98

I will try to explain my "secret understanding" the best way I can.

There are two entirely separate concepts here. One is the compiler's ability to replace a function call by repeating the function body directly at the call site. The other is the possibility of defining a function in more than one translation unit (= more than one .cpp file).

The first one is called function inlining. The second is the purpose of the inline keyword. Historically, the inline keyword was also a strong suggestion to the compiler that it should inline the function marked inline. As compilers became better at optimising, this functionality has receded, and using inline as a suggestion to inline a function is indeed obsolete. The compiler will happily ignore it and inline something else entirely if it finds that's a better optimisation.

I hope we've dealt with the explicit inline–inlining relationship. There is none in current code.

So, what is the actual purpose of the inline keyword? It's simple: a function marked inline can be defined in more than one translation unit without violating the One Definition Rule (ODR). Imagine these two files:

file1.cpp

int f() { return 42; }

int main()
{ return f(); }

file2.cpp

int f() { return 42; }

This command:

> gcc file1.cpp file2.cpp

Will produce a linker error, complaining that the symbol f is defined twice.

However, if you mark a function with the inline keyword, it specifically tells the compiler & linker: "You guys make sure that multiple identical definitions of this function do not result in any errors!"

So the following will work:

file1.cpp

inline int f() { return 42; }

int main()
{ return f(); }

file2.cpp

inline int f() { return 42; }

Compiling and linking these two files together will not produce any linker errors.

Notice that of course the definition of f doesn't have to be in the files verbatim. It can come from an #included header file instead:

f.hpp

inline int f() { return 42; }

file1.cpp

#include "f.hpp"

int main()
{ return f(); }

file2.cpp

#include "f.hpp"

Basically, to be able to write a function definition into a header file, you have to mark it as inline, otherwise it will lead to multiple definition errors.


The last piece of the puzzle is: why is the keyword actually spelled inline when it has nothing to do with inlining? The reason is simple: to inline a function (that is, to replace a call to it by repeating its body on the call site), the compiler must have the function's body in the first place.

C++ follows a separate compilation model, where the compiler doesn't have access to object files other than the one it's currently producing. Therefore, to be able to inline a function, its definition must be part of the current translation unit. If you want to be able to inline it in more than one translation unit, its definition has to be in all of them. Normally, this would lead to a multiple definition error. So if you put your function in a header and #include its definition everywhere to enable its inlining everywhere, you have to mark it as inline to prevent multiple definition errors.

Notice that even today, while a compiler will inline any function is sees fit, it must still have access to that function's definition. So while the inline keyword is not required as the hint "please inline this," you may still find you need to use it to enable the compiler to do the inlining if it chooses to do so. Without it, you might not be able to get the definition into the translation unit, and without the definition, the compiler simply cannot inline the function.

The compiler cannot. The linker can. Modern optimisation techniques include Link-Time Code Generation (a.k.a. Whole Program Optimisation), where the optimiser is run over all object files as part of the linking process, before the actual linking. In this step, all function definitions are of course available and inlining is perfectly possible without a single inline keyword being used anywhere in the program. But this optimisation is generally costly in build time, especially for large projects. With this in mind, relying solely on LTCG for inlining may not be the best option.


For completeness: I've cheated slightly in the first part. The ODR property is actually not a property of the inline keyword, but of inline functions (which is a term of the language). The rules for inline functions are:

  • Can be defined in multiple translation units without causing linker errors
  • Must be defined in every translation unit in which it is used
  • All its definitions must be token-for-token and entity-for-entity identical

The inline keyword turns a function into an inline function. Another way to mark a function as inline is to define (not just declare) it directly in a class definition. Such a function is inline automatically, even without the inline keyword.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • 3
    Great explanation in the last part of the answer! – Luchian Grigore Apr 22 '15 at 12:00
  • 2
    Very nice explanation, I was still using inline for very small functions being called a lot of times by the program. – Vinz Apr 22 '15 at 12:06
  • @tepples Thanks for the edit suggestion, but I left it to the end on purpose. I had to drive home the point that `inline` is not about function inlining in the compiler sense, and I feel *inline functions* make this murkier. – Angew is no longer proud of SO Apr 22 '15 at 15:03
  • The required diagnostics when the `inline` rules are broken should be mentioned. (in particular, that no diagnostic is required). Also, any post on `inline` should mention the points where it is implicit (template functions, functions defined in the body of a class/struct). Finally, `namespace{}` and its use replacing `inline` (especially in a compiler with identical comdat folding (or ICF)) and the pros/cons in comparison (pros: less fragile. cons: ICF is often iterative, and each layer of pseudo-inline requires an iteration) – Yakk - Adam Nevraumont Apr 22 '15 at 15:14
  • Also, `constexpr` functions and `=delete;`'d functions are implicitly inline. – T.C. Apr 22 '15 at 15:27
  • 1
    @Yakk Function templates are not implicitly `inline`; they have a separate ODR exemption. – T.C. Apr 22 '15 at 15:28
  • 6
    OTOH, currently careful manual tuning of inlining can still beat compilers (see [Andrei Alexandrescu's talk at CppCon 2014](https://www.youtube.com/watch?v=Qq_WaiwzOtI)) . But the small performance gain is only meaningful if you are Facebook or something on that scale, where a 0.3% performance loss is a serious regression. – T.C. Apr 22 '15 at 15:32
  • 1
    @T.C.: I think careful tuning will always beat "static" compilers. There are many situations where programmers will know things compilers cannot and vice versa, especially with regard to how often various pieces of code will run when used in expected fashion. Perhaps a more useful "directive" would be to let compilers know which pieces of code will be executed super-often versus rarely, rather than whether or not to inline, but I think compilers will always need some "help" to get optimal results. – supercat Apr 22 '15 at 16:29
  • @Angew: So, when I write inline int f() { return 42; } int main() { return f(); } in file1.cpp & inline int f() { return 42; } in file2.cpp both the functions are considered as separate (not identical) functions. right? – Destructor Sep 25 '15 at 16:13
  • 2
    @PravasiMeet No, they are actually the same function, that's the point. It has the same address in all the `.cpp` files (=translation units), and shares the same static variables (if any). It's simply one function, but its body must be present in all translation units which refer to it (e.g. call it or take its address). – Angew is no longer proud of SO Sep 25 '15 at 16:29
  • 2
    @Angew: In other words, to *potentially* inline a function (replace its calls by its body on the call sites) called in multiple `.cpp` files (translation units), the compiler needs the function definition in each `.cpp` file, but the linker allows only one function definition in the program (*One definition rule*), so we use the `inline` keyword to bypass the limitation of the linker. Bottom line: the `inline` keyword quiets the *linker* to allow function inlining when the function is called in multiple `.cpp` files. Did I get you right? – Géry Ogam Jan 05 '16 at 13:40
  • 1
    @Maggyero Practically speaking, yes. Purely formally, C++ itself also disallows multiple definitions, so `inline` "quiets" this part of C++. But that part is in C++ mainly because of linking, so in practice, what you say is accurate. – Angew is no longer proud of SO Jan 05 '16 at 13:54
  • @Angew: Alright. Two questions: 1. In your last comment you say that the function definition must be present in the `.cpp` files that *refer* to the function, so not only function *calls* `f()` but also function *adresses* `f` and `&f`, but what is the point for function adresses since they are not inlined (replaced by the function body) like function calls? 2. Apart from allowing function inlining in multiple `.cpp` files, are there any other situations where the `inline` keyword is used? (I cannot imagine another purpose for this keyword allowing multiple same definitions.) – Géry Ogam Jan 05 '16 at 14:21
  • 1
    @Maggyero 1. The standard speaks in terms of "odr-used," and taking the address constitutes odr-use, so the definition has to be there. Maybe that's for consistency more than necessity. 2. Practically, `inline` allows you to put the function into a header file. Whether it gets inlined or not depends on the compiler; this also allows header-only libraries to exist, for example. – Angew is no longer proud of SO Jan 05 '16 at 15:08
  • 2
    It would be useful to explain how and why it's different from using `static`. The issue is, you start with a rather useless example of duplicating the definition, which suggests that the point is defining different code in different places - which simply doesn't work with `inline`. I'd suggest starting with a point of this being different from using `static` keyword. It may be worth poinitng out that modern linkers are capable of inlining. – Frax Apr 28 '18 at 11:16
46

inline is mostly just an external linkage specifier now, for the reasons you stated.

So yes, it does have a use, but it's a different one than actually inlining functions. It allows you to define the same method multiple times between compilation units and properly link them together, instead of getting multiple definition errors.

//header.h
inline void foo() {}
void goo() {}

//cpp1.cpp
#include "header.h"

//cpp2.cpp
#include "header.h"

// foo is okay, goo breaks the one definition rule (ODR)

Actually forcing function inlining is up to the compiler, some might have support via specific attributes or pragmas or (__forceinline) or whatnot.

Simply put, it allows you to define functions in headers without breaking the ODR...

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 1
    Why is it able to always work for external linkage? Is it because the compiler/linker sees the definition errors would happen otherwise? – Panzercrisis Apr 22 '15 at 15:45
  • 1
    @Panzercrisis: Many linkers can support a concept of "weak definition", such that if a symbol is strongly defined the linker will ignore any weak definitions and squawk at a second strong definition, but if it's only weakly defined the linker will arbitrarily select a weak definition without complaining if many exist. This is a very useful concept, and one which can also be used to smooth over API differences (though it's not used as much as it could be). For example, passing floating-point values in FPU registers will be faster than passing them in main-CPU registers... – supercat Apr 22 '15 at 16:33
  • ...on an ARM with an FPU, but passing in main-CPU registers would be required for an arm without an FPU. One could make all callers work with all methods by specifying that functions which accept things in FPU registers must be defined with an altered name, and weakly define a function with the unaltered name which loads CPU registers into FPU registers and calls the altered version. Code which expects to pass things to another function in FPU registers would call a function with the altered name, and weakly define a function with the altered name that loads things into CPU regs... – supercat Apr 22 '15 at 16:37
  • ...and calls the unaltered one. Code which knows nothing about an FPU would simply use the unaltered name and expect things in CPU registers. Under that scenario, either kind of code could call either type of method. So far as I know, no ABI for the ARM actually works that way with regard to FPU usage, but such approaches are often useful in smoothing over similar issues. – supercat Apr 22 '15 at 16:39
  • 3
    @supercat I'm not sure if I'm following you... Would it be to much for you to create a separate question and answer it yourself? I think that an example of what you're talking about would be really helpful, cause I'm not certain that I'm understanding "weak definition" so everything that follows is increasingly hazy. – Jonathan Mee Apr 22 '15 at 17:13