3

All code From what I've read, A1 & A2 are identical, but I don't if A3 is identical to A2. I know the code will compile since all of the A classes are tmemplated.

Note: All of the class & method declarations are in a .h file.

template <typename _Ty>
class A1 {
public:
    A1();
    void foo() { ... }
};


template <typename _Ty>
class A2 {
public:
    A2();
    void foo();
};

template <typename _Ty>
inline void A2<_Ty>::foo() { ... }


template <typename _Ty>
class A3 {
public:
    A3();
    void foo();
};

template <typename _Ty>
void A3<_Ty>::foo() { ... } // note: No inline keyword here.

P.S. I've seen variants of this question on stackoverflow, but not this exact question.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
MarkB
  • 872
  • 5
  • 13
  • `inline` is only "optional" to the compiler, it doesn't *have* to `inline` anything, the keyword is a mere **suggestion** to the compiler that it can be inlined – Tony The Lion Apr 23 '12 at 14:06
  • 1
    @TonyTheLion: I think he is not really concerned with actual inlining but rather with the real use of `inline` in C++: not breaking the ODR if the function appears in multiple translation units. – David Rodríguez - dribeas Apr 23 '12 at 14:08
  • @TonyTheLion: There are scenarios where you **have** to specify inline keyword. See my answer. – SigTerm Apr 23 '12 at 14:52
  • See Herb Sutter's [Inline Redux](http://www.drdobbs.com/184403879) – Peter Wood Apr 24 '12 at 08:15

2 Answers2

8

Yes, it's meaningful, but doesn't have much effect when combined with templates.

The major effect of the inline keyword is to tell the compiler that this function may appear with the same definition in multiple compilation units, so it needs to be flagged as "select-one" for the linker (so you don't get multiple definition errors). Templates already have this feature.

inline also is a hint to the compiler that you think the function should be inlined, but the compiler usually makes the final decision on inlining optimizations on its own.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • But a good compiler will take whether a function is declared `inline` into account when making the decision. The only reason for not doing so is that the compiler really is better at making this decision than the programmer---that's not yet the case for any compiler I know. – James Kanze Apr 23 '12 at 14:46
  • @James: That's why I said "doesn't have *much* effect" instead of "doesn't have *any* effect". – Ben Voigt Apr 23 '12 at 15:23
  • @JamesKanze: There's of course no absolute best way, but compilers use heuristics to decide whether inlining is worth the effort or not (http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html -> grep for "heuristic"). Force-inlining really is a matter of Deep Optimization Wizardry and requires knowledge of a lot of topics: Speculative/Out of order Execution, Prefetching, Cache Hierarchies, Branch Target Buffers, Cache sizes, ... My experience is that compilers are smarter than 99% of programmers. – Sebastian Mach Apr 23 '12 at 15:26
  • @BenVoigt: And then constant propagation, dead code elimination, code transformations and interleaving with code at the caller site ... – Sebastian Mach Apr 23 '12 at 15:30
  • @BenVoigt Maybe our disagreement is between what is and what should be. Given the state of optimization in most current compilers, `inline` should have a significant effect. Whether it actually does is another question. – James Kanze Apr 23 '12 at 15:57
  • @phresnel I think if compilers used all of the optimization techniques currently known and available to them, it would be close, and the compiler possibly could do the job better than the programmer. Most don't, however, and are far from it. – James Kanze Apr 23 '12 at 15:59
  • @James: Fact is, if you want to make the inlining decision, you need to use a `forceinline` keyword, because `inline` is just a hint. – Ben Voigt Apr 23 '12 at 19:11
  • @BenVoigt Not really. You're providing additional information for optimization to the compiler. In the end, you still want the compiler to make the final decision; you're just providing vital information which wouldn't be available to the compiler otherwise (with most of the usual compilers, anyway) to allow it to better make that decision. A bit like `register` 25 years ago. (And hopefully `inline` will be just as redundant 25 years from now.) – James Kanze Apr 24 '12 at 07:22
  • @JamesKanze: Do _you_ know all the details on an assembler level that makes programs fast on a certain architecture? Do you know all those performance micro optimizations and bit twiddling hacks? Did you know that `xor eax, eax` is not faster anymore? Are you a master of loop inversion and splitting? Constant folding and strength reduction across function calls? Multiplication with the `lea` instruction? Do you write SSE friendly code? I seriously doubt that more than just 1% of programmers are better at optimization and have more knowledge than a modern compiler, esp. a cross platform one. – Sebastian Mach Apr 24 '12 at 09:54
  • @phresnel We're not talking about code generation optimizations. We're talking about telling the compiler that a certain function is frequently called, rather than letting it figure this out itself. The programmer still knows more about the global working of the program than the compiler. – James Kanze Apr 24 '12 at 10:13
  • @JamesKanze: When working in a team, he only knows in the moment he adds/removes `inline`. The compiler always knows. And in general, the calling sites are so different that for each call it is different whether `inline` or not is ideal. And then there is the fact that non-inline can be faster or slower, depending on cache size and cache miss penalty and probabilities thereof (and more), the same can be said for inlined code: Can be faster or slower, it depends. Taking only the temporal frequency of calls as a measure about whether to inline or not is plain wrong on x86/amd64 machines. – Sebastian Mach Apr 24 '12 at 11:03
  • @JamesKanze: And yes: It is all the general and specific optimizations that influence the potential gain of inline/not-inline. E.g.: Inlining might enable a constant folding, which enables to remove a conditional that's alway true, making some call a hotspot. Another call tree might yield false in the conditional on average. Yet another might have the code of the function in execution cache already, etc. etc.. – Sebastian Mach Apr 24 '12 at 11:23
  • @phresnel When working in a team, you don't use `inline` until the profiler says you have to. In theory, a compiler could use this profiler output, but in practice, most don't. Regardless of the theories, the fact remains that with current compilers, the programmer knows more than the compiler. Judicious use of `inline` improves performance, at least when the compilers take it into account. – James Kanze Apr 24 '12 at 12:10
  • @JamesKanze: At least one of the three major compilers (g++) has PGO. And I really doubt that any programmer in a larger scale x86/64 software can judge that adding an `inline` improves performance _before_ _testing_ it (not even if used in only one place, but especially not if the places diverge structurally), because an inlined function does not automatically give higher performance (not even if used judiciously). Inlined functions have a cost, too, and this can often enough outweigh their gain by magnitudes. – Sebastian Mach Apr 24 '12 at 14:03
  • @phresnel: Many functions obviously benefit from inlining (accessors providing read-only access to private primitive members, for example). Of course, it should be equally straightforward for the developer or compiler to notice this. – Ben Voigt Apr 24 '12 at 14:07
  • @phresnel One doesn't add `inline` before testing it; `inline` is an optimization step, and you only optimize once you've got data from the profiler. (And g++ isn't particularly good with regards to optimization; just average.) – James Kanze Apr 24 '12 at 16:02
  • @BenVoigt: True, but another many functions benefit from not being inlined, most commonly when the inlined code is conditional. My point primarily is: Whether inlining is beneficial or not largely depends on the calling site, not in the inlined(or not) function itself. The same function might perform better at point A when inlined, but worse at point B, and equally at point C. – Sebastian Mach Apr 24 '12 at 18:12
  • @JamesKanze: Sure? http://macles.blogspot.de/2010/08/intel-atom-icc-gcc-clang.html (author doesn't use optimal flags, tho), www.equalizergraphics.com/documents/WhitePapers/OpenMP_ICC.pdf , http://www.phoronix.com/scan.php?page=article&item=gcc_46_llvm29&num=8 , http://www.phoronix.com/scan.php?page=article&item=linux_compiler_deathmatch&num=1 , http://www.phoronix.com/scan.php?page=article&item=apple_llvm_gcc&num=2 . I would say: On average, gcc is almost en par with its competition. Where do you got your impression from? – Sebastian Mach Apr 24 '12 at 18:24
  • @phresnel gcc is about on par with VC++ or Sun CC. Neither of which are particularly good at optimizing either. More advanced techniques are known, but are not widely used. Until they are, compilers would do well to respect `inline`, or take it into account, because the compiler won't be able to obtain the relevant information otherwise. – James Kanze Apr 25 '12 at 07:30
  • @JamesKanze: Can you maybe refer to an up-to-date comparison between gcc and icc (or which compiler are you refering to?)? I found another one: http://www.linuxforge.net/docs/bm/bench-gcc-icc.php . You claim more and more, yet lack any evidence, and I am building up the impression that your knowledge is big but not up-to-date or based on rumors (if you have evidence, I am the last one to not respect it) – Sebastian Mach Apr 25 '12 at 07:54
  • @phresnel If you compare gcc with other "average" compilers, it is similar. For various reasons, most wide-spread compilers don't use the most advanced optimization techniques. That doesn't mean that the techniques aren't known. (And is this bait and switch, or what? The issue is whether gcc optimization is good enough to justify ignoring `inline`. It definitely isn't.) – James Kanze Apr 25 '12 at 12:27
  • @JamesKanze: I think the inline/gcc discussion is a dead end with us two ;) But can you name a non-average compiler that wasn't covered in any of the links I posted? – Sebastian Mach Apr 25 '12 at 14:22
0

Is inline keyword meaningful if function is defined in header file?

It is. Following project will produce linker error on both msvc and g++ BECAUSE of the omission of inline keyword:


main.cpp:

#include "a.h"

int main(int argc, char** argv){
    A obj;
    obj.f();
    a();
    b();
    return 0;
}

a.h:

#ifndef A_HEADER
#define A_HEADER

class A{
public:
    void f();
};

void a(){
}

void b();

void A::f(){
}

#endif

b.cpp:

#include "a.h"

void b(){
    A obj;
    obj.f();
    a();
}

*.pro file (for Qt 4 build system):

TEMPLATE = app
TARGET = 
DEPENDPATH += .
INCLUDEPATH += .

HEADERS += a.h
SOURCES += b.cpp main.cpp

Compilation output:

cl.exe:


main.obj : error LNK2005: "void __cdecl a(void)" (?a@@YAXXZ) already defined in b.obj
main.obj : error LNK2005: "public: void __thiscall A::f(void)" (?f@A@@QAEXXZ) already defined in b.obj
debug\1234.exe : fatal error LNK1169: one or more multiply defined symbols found

g++:


debug/main.o: In function `Z1av':
D:\c++\1234/a.h:6: multiple definition of `a()'
debug/b.o:D:\c++\1234/a.h:6: first defined here
debug/main.o:D:\c++\1234/a.h:11: multiple definition of `A::f()'
debug/b.o:D:\c++\1234/a.h:11: first defined here
collect2: ld returned 1 exit status
make[1]: *** [debug/1234.exe] Error 1
make: *** [debug] Error 2

Now, why do you think this happens? Because compiler inserts contents of header file into *.cpp file when compiling. Since function isn't "inline", its name is made known to the linker, and each .obj/.o file will get its own unique copy of A::f() and a(). Linker won't know which you're supposed to use and will complain. If you make functions inline, everything will work fine.

However, templates are another story.

SigTerm
  • 26,089
  • 6
  • 66
  • 115
  • duplicate of http://stackoverflow.com/a/1759575/103167 The non-template case is already well explained in other questions. – Ben Voigt Apr 23 '12 at 15:24