C++ inline is totally different to C inline.
#include <iostream>
extern inline int i[];
int i [5];
struct c {
int function (){return 1;} // implicitly inline
static inline int j = 3; // explicitly inline
static int k; // without inline, a static member has to be defined out of line
static int f (){return 1;} // but a static method does not // implicitly inline
};
extern inline int b;
int b=3;
int c::k = 3; // when a static member is defined out of line it cannot have a static
// specifier and if it doesn't have an `inline` specifier in the
// declaration or on the definition then it is not inline and always
// emits a strong global symbol in the translation unit
int main() {
c j;
std::cout << i;
}
inline
on its own affects the compiler, assembler and the linker. It is a directive to the compiler saying only emit a symbol for this function/data if it's used in the translation unit, and if it is, then like class methods, tell the assembler to store them in the section .section .text.c::function(),"axG",@progbits,c::function(),comdat
or .section .bss.i,"awG",@nobits,i,comdat
for unitialised data or .section .data.b,"awG",@progbits,b,comdat
for initialised data. Template instantiations also go in their own comdat groups.
This follows .section name, "flags"MG, @type, entsize, GroupName[, linkage]
. For instance, the section name is .text.c::function()
. axG
means the section is allocatable, executable and in a group i.e. a group name will be specified (and there is no M flag so no entsize will be specified); @progbits
means the section contains data and isn't blank; c::function()
is the group name and the group has comdat
linkage meaning that in all object files, all sections encountered with this group name tagged with comdat will be removed from the final executable except for 1 i.e. the compiler makes sure that there is only one definition in the translation unit and then tells the assembler to put it in its own group in the object file (1 section in 1 group) and then the linker will make sure that if any object files have a group with the same name, then only include one in the final .exe. The difference between inline
and not using inline
is now visible to the assembler and as a result the linker, because it's not stored in the regular .data
or .text
etc by the assembler due to their directives. Only inline symbols with external linkage are given external comdat linkage like this -- static linkage (local) symbols do not need to go in comdat groups.
inline
on a non-static method declaration in a class makes the method inline if it is defined out-of-line, this will prevent the method being emitted in the translation unit if it is not referenced in the translation unit. The same effect is achieved by putting inline
on the out-of-line definition. When a method is defined out-of-line without an inline
specifier and the declaration in the class is not inline
then it will emit a symbol for the method in the translation unit at all times because it will have external linkage rather than external comdat linkage. If the method is defined in the class then it is implicitly inline
, which gives it external comdat linkage rather than external linkage.
static inline
on a member in a class (as opposed to method) makes it a static
member (which does not refer to its linkage -- it has the linkage of its class which may be extern). static inline
also allows static
members of the class to be defined inside the class instead of needing to be declared in the class and then defined out-of-line (without static
in the definition, which wasn't allowed without -fpermissive
). *static inline*
also makes the members inline
and not static inline
-- inline
means that the definition is only emitted if it is referenced in the translation unit. Previously you had to specify inline
on the out-of-line definition to make the member inline
.
Seeing as static
methods can be defined in the class, static inline
has no effect on the static
method defined in the class, which always has external linkage, is a static method and is inline
. If it is defined out of line then inline
must be used to make it inline
(i.e. to give to external comdat linkage rather than just external linkage), and static
still can't be used.
static inline
at file scope only affects the compiler. It means to the compiler: only emit a symbol for this function/data if it's used in the translation unit and do so as a regular static symbol (store in.text /.data without .globl directive). To the assembler there is now no difference between static
and static inline
. Like the other forms of inline
, it cannot be used on a class
, which is a type, but can be used on an object of the type of that class. This form of static inline
also cannot be used on members or methods of a function, where it will always be treated inline
as the static
means something else in a class (it means that the class is acting as a scope rather than it being a member of or method to be used on an object).
extern inline
is a declaration that means you must define this symbol in the translation unit if it is referenced or throw compiler error; if it's defined then treat it as a regular inline
and to the assembler and linker there will be no difference between extern inline
and inline
, so this is a compiler guard only.
extern inline int i[];
extern int i[]; //allowed repetition of declaration with incomplete type, inherits inline property
extern int i[5]; //declaration now has complete type
extern int i[5]; //allowed redeclaration if it is the same complete type or has not yet been completed
extern int i[6]; //error, redeclaration with different complete type
int i[5]; //definition, must have complete type and same complete type as the declaration if there is a declaration with a complete type
The whole of the above without the error line collapses to inline int i[5]
. Obviously if you did extern inline int i[] = {5};
then extern
would be ignored due to the explicit definition through assignment.
I think the reason that static
is not allowed on a static
out-of-line definition without -fpermissive
is because it implies that the static refers to static
linkage, because it's not immediately obvious to the programmer that it is a member of a class or whether that class has , where the static
means something different. -fpermissive
ignores the static
specifier on the out-of-line definition and it means nothing. In the case of a simple integer, k
can't be defined out of a namespace, if c
were a namespace, but if k
were a function, then there would be no way of visibly telling from the line of code whether it is an out of line definition of a function in a namespace with static
linkage, or an out-of-line definition of a static member with external linkage, and may give the wrong impression to the programmer / reader of the code.
For local classes, inline
on a member / method will result in a compiler error and members and methods have no linkage.
For inline
on a namespace, see this and this
inline
(9.3/2). – Lightness Races in Orbit