In this link, what is an inline function and what is the inline keyword is explained. I'm reading through it because I realized I've never understood the meaning of these two concepts and how they should be used in practice. I'm quoting and commenting from the link I provided
An inline function or inline variable (since C++17) is a function or variable (since C++17) with the following properties:
1) There may be more than one definition of an inline function or variable (since C++17) in the program as long as each definition appears in a different translation unit. For example, an inline function or an inline variable (since C++17) may be defined in a header file that is include'd in multiple source files.
Here I already have understanding problems, declaration is the specification of new identifiers like
void func(void);
while a definition is the actual implementation, including the body
void func(void) { //some code... }
The point 1) means that I can give different implementation as long as they're in different translation units (i.e. one implementation per header e per source files), but I'm puzzled in the case I have a source file source.cc
with a declaration for func
and an header file with another declaration of func
the translation unit is the pair source.cc+header.h
and in such a case having declared two times func
doesn't make any sense, is that right?
2) The definition of an inline function or variable (since C++17) must be present in the translation unit where it is accessed (not necessarily before the point of access).
This is the usual case where I separate definition from declaration, the first in an header file, the second one is in the source file, if I need to use the function I have to include only the header right? The access point would be provided by the source during the linking phase, correct?
3) An inline function or variable (since C++17) with external linkage (e.g. not declared static) has the following additional properties: 1) It must be declared inline in every translation unit. 2) It has the same address in every translation unit.
Could you provide a simple example of what this means? I can't picture a practical case of such a case. The case 3) states that the keyword inline
is mandatory unless the function to be declared is static.
Is everything I said so far correct?
In practice a function should be inline when such a function is very small, but not always the compiler would inline the function declared as inline, for example if it has loops inside or recursion (Effective C++ states so). In general then it's compiler dependent, I the wonder now...
Say I have two functions the first one is self-contained (it doesn't internally call any-other function), the second one call's the first one (you can assume they're both 10 lines for sake of argument). Should both of them declared inline? should they be declared in an header file? or should I separate definition in an header file and the implementation in an source file? What would be better?
Edit 1:
Following one of the answer is better if I work by examples, with related assembly code analysis.
I removed the previous code because it was meaningless (the -O3
flag optimization wasn't set).
I start again... I have 5 files header.h
,src.cc
, src1.cc
, src2.cc
and main.cc
. For each translation unit the related assembly code is posted.
I've manipulated such files in three different ways and later observed the assembly code generated, this helped me to understand how the inline keyword works.
Example 1:
header.h
#ifndef HEADER_H_ #define HEADER_H_ int func(int a, int b); int test_1(); int test_2(); #endif /* HEADER_H_ */
src.cc
#include "header.h" int func(int a, int b) { return a + b; }
src1.cc
#include "header.h" int test_1() { int a, b, c; a = 3; b = 7; c = func(a, b); return c; }
src2.cc
#include "header.h" int test_2() { int a, b, c; a = 7; b = 8; c = func(a, b); return c; }
main.cc
int main(int argc, char** argv) { test_1(); test_2(); test_1(); test_2(); }
Assembly 1:
src.s
GAS LISTING /tmp/cc0j97WY.s page 1 1 .file "src.cc" 2 .text 3 .align 2 4 .p2align 4,,15 5 .globl _Z4funcii 6 .type _Z4funcii, @function 7 _Z4funcii: 8 .LFB2: 9 0000 8D043E leal (%rsi,%rdi), %eax 10 0003 C3 ret 11 .LFE2: 12 .size _Z4funcii, .-_Z4funcii 13 .globl __gxx_personality_v0 14 .section .eh_frame,"a",@progbits 15 .Lframe1: 16 0000 1C000000 .long .LECIE1-.LSCIE1 17 .LSCIE1: 18 0004 00000000 .long 0x0 19 0008 01 .byte 0x1 20 0009 7A505200 .string "zPR" 21 000d 01 .uleb128 0x1 22 000e 78 .sleb128 -8 23 000f 10 .byte 0x10 24 0010 06 .uleb128 0x6 25 0011 03 .byte 0x3 26 0012 00000000 .long __gxx_personality_v0 27 0016 03 .byte 0x3 28 0017 0C .byte 0xc 29 0018 07 .uleb128 0x7 30 0019 08 .uleb128 0x8 31 001a 90 .byte 0x90 32 001b 01 .uleb128 0x1 33 001c 00000000 .align 8 34 .LECIE1: 35 .LSFDE1: 36 0020 14000000 .long .LEFDE1-.LASFDE1 37 .LASFDE1: 38 0024 24000000 .long .LASFDE1-.Lframe1 39 0028 00000000 .long .LFB2 40 002c 04000000 .long .LFE2-.LFB2 41 0030 00 .uleb128 0x0 42 0031 00000000 .align 8 42 000000 43 .LEFDE1: 44 .ident "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)" 45 .section .note.GNU-stack,"",@progbits
src1.s
GAS LISTING /tmp/cchSilt1.s page 1 1 .file "src1.cc" 2 .text 3 .align 2 4 .p2align 4,,15 5 .globl _Z6test_1v 6 .type _Z6test_1v, @function 7 _Z6test_1v: 8 .LFB2: 9 0000 BE070000 movl $7, %esi 9 00 10 0005 BF030000 movl $3, %edi 10 00 11 000a E9000000 jmp _Z4funcii 11 00 12 .LFE2: 13 .size _Z6test_1v, .-_Z6test_1v 14 .globl __gxx_personality_v0 15 .section .eh_frame,"a",@progbits 16 .Lframe1: 17 0000 1C000000 .long .LECIE1-.LSCIE1 18 .LSCIE1: 19 0004 00000000 .long 0x0 20 0008 01 .byte 0x1 21 0009 7A505200 .string "zPR" 22 000d 01 .uleb128 0x1 23 000e 78 .sleb128 -8 24 000f 10 .byte 0x10 25 0010 06 .uleb128 0x6 26 0011 03 .byte 0x3 27 0012 00000000 .long __gxx_personality_v0 28 0016 03 .byte 0x3 29 0017 0C .byte 0xc 30 0018 07 .uleb128 0x7 31 0019 08 .uleb128 0x8 32 001a 90 .byte 0x90 33 001b 01 .uleb128 0x1 34 001c 00000000 .align 8 35 .LECIE1: 36 .LSFDE1: 37 0020 14000000 .long .LEFDE1-.LASFDE1 38 .LASFDE1: 39 0024 24000000 .long .LASFDE1-.Lframe1 40 0028 00000000 .long .LFB2 41 002c 0F000000 .long .LFE2-.LFB2 42 0030 00 .uleb128 0x0 43 0031 00000000 .align 8 43 000000 44 .LEFDE1: 45 .ident "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)" 46 .section .note.GNU-stack,"",@progbits
src2.s
GAS LISTING /tmp/cc2JMtt3.s page 1 1 .file "src2.cc" 2 .text 3 .align 2 4 .p2align 4,,15 5 .globl _Z6test_2v 6 .type _Z6test_2v, @function 7 _Z6test_2v: 8 .LFB2: 9 0000 BE080000 movl $8, %esi 9 00 10 0005 BF070000 movl $7, %edi 10 00 11 000a E9000000 jmp _Z4funcii 11 00 12 .LFE2: 13 .size _Z6test_2v, .-_Z6test_2v 14 .globl __gxx_personality_v0 15 .section .eh_frame,"a",@progbits 16 .Lframe1: 17 0000 1C000000 .long .LECIE1-.LSCIE1 18 .LSCIE1: 19 0004 00000000 .long 0x0 20 0008 01 .byte 0x1 21 0009 7A505200 .string "zPR" 22 000d 01 .uleb128 0x1 23 000e 78 .sleb128 -8 24 000f 10 .byte 0x10 25 0010 06 .uleb128 0x6 26 0011 03 .byte 0x3 27 0012 00000000 .long __gxx_personality_v0 28 0016 03 .byte 0x3 29 0017 0C .byte 0xc 30 0018 07 .uleb128 0x7 31 0019 08 .uleb128 0x8 32 001a 90 .byte 0x90 33 001b 01 .uleb128 0x1 34 001c 00000000 .align 8 35 .LECIE1: 36 .LSFDE1: 37 0020 14000000 .long .LEFDE1-.LASFDE1 38 .LASFDE1: 39 0024 24000000 .long .LASFDE1-.Lframe1 40 0028 00000000 .long .LFB2 41 002c 0F000000 .long .LFE2-.LFB2 42 0030 00 .uleb128 0x0 43 0031 00000000 .align 8 43 000000 44 .LEFDE1: 45 .ident "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)" 46 .section .note.GNU-stack,"",@progbits
main.s
GAS LISTING /tmp/cc5CfYBW.s page 1 1 .file "main.cc" 2 .text 3 .align 2 4 .p2align 4,,15 5 .globl main 6 .type main, @function 7 main: 8 .LFB2: 9 0000 4883EC08 subq $8, %rsp 10 .LCFI0: 11 0004 E8000000 call _Z6test_1v 11 00 12 0009 E8000000 call _Z6test_2v 12 00 13 000e E8000000 call _Z6test_1v 13 00 14 .p2align 4,,5 15 0013 E8000000 call _Z6test_2v 15 00 16 0018 31C0 xorl %eax, %eax 17 001a 4883C408 addq $8, %rsp 18 .p2align 4,,1 19 001e C3 ret 20 .LFE2: 21 .size main, .-main 22 .globl __gxx_personality_v0 23 .section .eh_frame,"a",@progbits 24 .Lframe1: 25 0000 1C000000 .long .LECIE1-.LSCIE1 26 .LSCIE1: 27 0004 00000000 .long 0x0 28 0008 01 .byte 0x1 29 0009 7A505200 .string "zPR" 30 000d 01 .uleb128 0x1 31 000e 78 .sleb128 -8 32 000f 10 .byte 0x10 33 0010 06 .uleb128 0x6 34 0011 03 .byte 0x3 35 0012 00000000 .long __gxx_personality_v0 36 0016 03 .byte 0x3 37 0017 0C .byte 0xc 38 0018 07 .uleb128 0x7 39 0019 08 .uleb128 0x8 40 001a 90 .byte 0x90 41 001b 01 .uleb128 0x1 42 001c 00000000 .align 8 43 .LECIE1: 44 .LSFDE1: 45 0020 14000000 .long .LEFDE1-.LASFDE1 46 .LASFDE1: 47 0024 24000000 .long .LASFDE1-.Lframe1 48 0028 00000000 .long .LFB2 49 002c 1F000000 .long .LFE2-.LFB2 50 0030 00 .uleb128 0x0 51 0031 44 .byte 0x4 52 .long .LCFI0-.LFB2 53 0032 0E .byte 0xe GAS LISTING /tmp/cc5CfYBW.s page 2 54 0033 10 .uleb128 0x10 55 0034 00000000 .align 8 56 .LEFDE1: 57 .ident "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)" 58 .section .note.GNU-stack,"",@progbits
Example 2:
header.h
#ifndef HEADER_H_ #define HEADER_H_ inline int func(int a, int b) { return a + b; } int test_1(); int test_2(); #endif /* HEADER_H_ */
src.cc
#include "header.h" /* int func(int a, int b) { return a + b; }*/
src1.cc
#include "header.h" int test_1() { int a, b, c; a = 3; b = 7; c = func(a, b); return c; }
src2.cc
#include "header.h" int test_2() { int a, b, c; a = 7; b = 8; c = func(a, b); return c; }
main.cc
int main(int argc, char** argv) { test_1(); test_2(); test_1(); test_2(); }
Assembly 2:
src.s
GAS LISTING /tmp/cczLx8os.s page 1 1 .file "src.cc" 2 .ident "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)" 3 .section .note.GNU-stack,"",@progbits
src1.s
GAS LISTING /tmp/ccMFMy9s.s page 1 1 .file "src1.cc" 2 .text 3 .align 2 4 .p2align 4,,15 5 .globl _Z6test_1v 6 .type _Z6test_1v, @function 7 _Z6test_1v: 8 .LFB3: 9 0000 B80A0000 movl $10, %eax 9 00 10 0005 C3 ret 11 .LFE3: 12 .size _Z6test_1v, .-_Z6test_1v 13 .globl __gxx_personality_v0 14 .section .eh_frame,"a",@progbits 15 .Lframe1: 16 0000 1C000000 .long .LECIE1-.LSCIE1 17 .LSCIE1: 18 0004 00000000 .long 0x0 19 0008 01 .byte 0x1 20 0009 7A505200 .string "zPR" 21 000d 01 .uleb128 0x1 22 000e 78 .sleb128 -8 23 000f 10 .byte 0x10 24 0010 06 .uleb128 0x6 25 0011 03 .byte 0x3 26 0012 00000000 .long __gxx_personality_v0 27 0016 03 .byte 0x3 28 0017 0C .byte 0xc 29 0018 07 .uleb128 0x7 30 0019 08 .uleb128 0x8 31 001a 90 .byte 0x90 32 001b 01 .uleb128 0x1 33 001c 00000000 .align 8 34 .LECIE1: 35 .LSFDE1: 36 0020 14000000 .long .LEFDE1-.LASFDE1 37 .LASFDE1: 38 0024 24000000 .long .LASFDE1-.Lframe1 39 0028 00000000 .long .LFB3 40 002c 06000000 .long .LFE3-.LFB3 41 0030 00 .uleb128 0x0 42 0031 00000000 .align 8 42 000000 43 .LEFDE1: 44 .ident "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)" 45 .section .note.GNU-stack,"",@progbits
src2.s
GAS LISTING /tmp/ccNXXmLv.s page 1 1 .file "src2.cc" 2 .text 3 .align 2 4 .p2align 4,,15 5 .globl _Z6test_2v 6 .type _Z6test_2v, @function 7 _Z6test_2v: 8 .LFB3: 9 0000 B80F0000 movl $15, %eax 9 00 10 0005 C3 ret 11 .LFE3: 12 .size _Z6test_2v, .-_Z6test_2v 13 .globl __gxx_personality_v0 14 .section .eh_frame,"a",@progbits 15 .Lframe1: 16 0000 1C000000 .long .LECIE1-.LSCIE1 17 .LSCIE1: 18 0004 00000000 .long 0x0 19 0008 01 .byte 0x1 20 0009 7A505200 .string "zPR" 21 000d 01 .uleb128 0x1 22 000e 78 .sleb128 -8 23 000f 10 .byte 0x10 24 0010 06 .uleb128 0x6 25 0011 03 .byte 0x3 26 0012 00000000 .long __gxx_personality_v0 27 0016 03 .byte 0x3 28 0017 0C .byte 0xc 29 0018 07 .uleb128 0x7 30 0019 08 .uleb128 0x8 31 001a 90 .byte 0x90 32 001b 01 .uleb128 0x1 33 001c 00000000 .align 8 34 .LECIE1: 35 .LSFDE1: 36 0020 14000000 .long .LEFDE1-.LASFDE1 37 .LASFDE1: 38 0024 24000000 .long .LASFDE1-.Lframe1 39 0028 00000000 .long .LFB3 40 002c 06000000 .long .LFE3-.LFB3 41 0030 00 .uleb128 0x0 42 0031 00000000 .align 8 42 000000 43 .LEFDE1: 44 .ident "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)" 45 .section .note.GNU-stack,"",@progbits
main.s
GAS LISTING /tmp/cc2cc5rp.s page 1 1 .file "main.cc" 2 .text 3 .align 2 4 .p2align 4,,15 5 .globl main 6 .type main, @function 7 main: 8 .LFB3: 9 0000 4883EC08 subq $8, %rsp 10 .LCFI0: 11 0004 E8000000 call _Z6test_1v 11 00 12 0009 E8000000 call _Z6test_2v 12 00 13 000e E8000000 call _Z6test_1v 13 00 14 .p2align 4,,5 15 0013 E8000000 call _Z6test_2v 15 00 16 0018 31C0 xorl %eax, %eax 17 001a 4883C408 addq $8, %rsp 18 .p2align 4,,1 19 001e C3 ret 20 .LFE3: 21 .size main, .-main 22 .globl __gxx_personality_v0 23 .section .eh_frame,"a",@progbits 24 .Lframe1: 25 0000 1C000000 .long .LECIE1-.LSCIE1 26 .LSCIE1: 27 0004 00000000 .long 0x0 28 0008 01 .byte 0x1 29 0009 7A505200 .string "zPR" 30 000d 01 .uleb128 0x1 31 000e 78 .sleb128 -8 32 000f 10 .byte 0x10 33 0010 06 .uleb128 0x6 34 0011 03 .byte 0x3 35 0012 00000000 .long __gxx_personality_v0 36 0016 03 .byte 0x3 37 0017 0C .byte 0xc 38 0018 07 .uleb128 0x7 39 0019 08 .uleb128 0x8 40 001a 90 .byte 0x90 41 001b 01 .uleb128 0x1 42 001c 00000000 .align 8 43 .LECIE1: 44 .LSFDE1: 45 0020 14000000 .long .LEFDE1-.LASFDE1 46 .LASFDE1: 47 0024 24000000 .long .LASFDE1-.Lframe1 48 0028 00000000 .long .LFB3 49 002c 1F000000 .long .LFE3-.LFB3 50 0030 00 .uleb128 0x0 51 0031 44 .byte 0x4 52 .long .LCFI0-.LFB3 53 0032 0E .byte 0xe GAS LISTING /tmp/cc2cc5rp.s page 2 54 0033 10 .uleb128 0x10 55 0034 00000000 .align 8 56 .LEFDE1: 57 .ident "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)" 58 .section .note.GNU-stack,"",@progbits
Example 3:
header.h
#ifndef HEADER_H_ #define HEADER_H_ inline int func(int a, int b) { return a + b; } inline int test_1() { int a, b, c; a = 3; b = 7; c = func(a, b); return c; } inline int test_2() { int a, b, c; a = 7; b = 8; c = func(a, b); return c; } #endif /* HEADER_H_ */
src.cc
#include "header.h" /* int func(int a, int b) { return a + b; }*/
src1.cc
#include "header.h" /*int test_1() { int a, b, c; a = 3; b = 7; c = func(a, b); return c; }*/
src2.cc
#include "header.h" /*int test_2() { int a, b, c; a = 7; b = 8; c = func(a, b); return c; }*/
main.cc
int main(int argc, char** argv) { test_1(); test_2(); test_1(); test_2(); }
Assembly 3:
src.s
GAS LISTING /tmp/ccfPkzMC.s page 1 1 .file "src.cc" 2 .ident "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)" 3 .section .note.GNU-stack,"",@progbits
src1.s
GAS LISTING /tmp/cckRkoWG.s page 1 1 .file "src1.cc" 2 .ident "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)" 3 .section .note.GNU-stack,"",@progbits
src2.s
GAS LISTING /tmp/ccfmb3gI.s page 1 1 .file "src2.cc" 2 .ident "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)" 3 .section .note.GNU-stack,"",@progbits
main.s
GAS LISTING /tmp/ccGBsR8z.s page 1 1 .file "main.cc" 2 .text 3 .align 2 4 .p2align 4,,15 5 .globl main 6 .type main, @function 7 main: 8 .LFB5: 9 0000 31C0 xorl %eax, %eax 10 0002 C3 ret 11 .LFE5: 12 .size main, .-main 13 .globl __gxx_personality_v0 14 .section .eh_frame,"a",@progbits 15 .Lframe1: 16 0000 1C000000 .long .LECIE1-.LSCIE1 17 .LSCIE1: 18 0004 00000000 .long 0x0 19 0008 01 .byte 0x1 20 0009 7A505200 .string "zPR" 21 000d 01 .uleb128 0x1 22 000e 78 .sleb128 -8 23 000f 10 .byte 0x10 24 0010 06 .uleb128 0x6 25 0011 03 .byte 0x3 26 0012 00000000 .long __gxx_personality_v0 27 0016 03 .byte 0x3 28 0017 0C .byte 0xc 29 0018 07 .uleb128 0x7 30 0019 08 .uleb128 0x8 31 001a 90 .byte 0x90 32 001b 01 .uleb128 0x1 33 001c 00000000 .align 8 34 .LECIE1: 35 .LSFDE1: 36 0020 14000000 .long .LEFDE1-.LASFDE1 37 .LASFDE1: 38 0024 24000000 .long .LASFDE1-.Lframe1 39 0028 00000000 .long .LFB5 40 002c 03000000 .long .LFE5-.LFB5 41 0030 00 .uleb128 0x0 42 0031 00000000 .align 8 42 000000 43 .LEFDE1: 44 .ident "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)" 45 .section .note.GNU-stack,"",@progbits
Example 1 and example 3 are the ones I'm particularly interested in, because they should highlight somehow what is the difference between an inline function and a not inline function (following the points 1,2 and 3 of the link I posted above), I don't see any lack of properties in the not inline functions compared to the inline version. Can someone highlight the difference for me (again in terms of the points 1,2 and 3)?
The inline keyword tells the compiler to substitute the code within the function definition for every instance of a function call. Using inline functions can make your program faster because they eliminate the overhead associated with function calls.
In an inline function, a function call is replaced by the actual program code. Most of the Inline functions are used for small computations. They are not suitable for large computing. An inline function is similar to a normal function. The only difference is that we place a keyword inline before the function name.
Explanation of the Program In the above program, the function setNum() is declared as an inline function using the keyword “inline”. This function simply returns an integer. When a call to this inline function is made, the compiler replaces the calling statement with the definition of the inline function setNum().
Maybe a few examples would help.
foo.h:
extern int x; int * f();
foo.cpp:
#include "foo.h" int x = 25; int * f() { return &x; }
Users include foo.h
and need to link in the translation unit containing foo.cpp
in order to call f
. Every such call returns the same address.
foo.h:
static int x = 35; static int * f() { return &x; }
Every TU that includes foo.h
gets a separate and distinct function f
, calling which results in a unique value per TU.
foo.h:
static int x = 45; inline int * f() { return &x; }
This appears to be a header-only library, but if foo.h
is included in more than one TU, this constitutes an ODR violation, since f
would be defined more than once but not all of its definitions would be identical.
This is a common mistake. Workarounds include things like making x
a template or replacing x
with a function like int & x() { static int impl = 45; return impl; }
. Note that if you omit the static
, you would most likely get a linker error because of multiple definitions of x
; static
seemingly "makes the code compile".
foo.h:
inline int x = 55; inline int * f() { return &x; }
This version is functionally equivalent to (1), but does not require a dedicated translation unit to contain the definitions of x
and f
.
The point 1) means that I can give different implementation as long as they're in different translation units
No, it says you can have more than one implementation. It does not say they can be different. The implementations must all be identical.
I'm puzzled in the case I have a source file
source.cc
with a declaration forfunc
and an header file with another declaration offunc
the translation unit is the pairsource.cc+header.h
and in such a case having declared two timesfunc
doesn't make any sense, is that right?
You can declare a function as many times as you like, in as many translation units as you like, regardless of whether or not it is inline. Inline is not a factor here.
2) The definition of an inline function or variable (since C++17) must be present in the translation unit where it is accessed.
This is the usual case where I separate definition from declaration, the first in an header file, the second one is in the source file, if I need to use the function I have to include only the header right? The access point would be provided by the source during the linking phase, correct?
No, the definition of an inline function must be present in every TU that uses it, before the linking phase. It is the purpose of inline functions to allow definitions in multiple TUs; you use inline
when you want to put the definition of a function in a header.
The case 3) states that the keyword inline is mandatory unless the function to be declared is static.
No, it doesn't say that at all, I don't know how you could have interpreted it that way. It just says that an inline
static
function has internal linkage, and an inline
non-static
function has external linkage, and subpoints 3.1 and 3.2 apply to inline
functions with external linkage.
In practice a function should be inline when such a function is very small, but not always the compiler would inline the function declared as inline, for example if it has loops inside or recursion (Effective C++ states so). In general then it's compiler dependent, I the wonder now...
Say I have two functions the first one is self-contained (it doesn't internally call any-other function), the second one call's the first one (you can assume they're both 10 lines for sake of argument). Should both of them declared inline? should they be declared in an header file? or should I separate definition in an header file and the implementation in an source file? What would be better?
Whether or not the optimizer will perform inline substitution of a function body is not strongly correlated with whether it is an inline
function. The optimizer will figure out for itself whether to perform inline substitution of a function, regardless of whether or not it is an inline
function. You declare functions inline
if you want to put their definition in a header.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With