Let's start with the following set of C++ files:
// my_class.h
struct MyClass
{
void my_func();
};
void MyClass::my_func()
{}
// f.h
void f1();
void f2();
// f1.cpp
#include "my_class.h"
void f1()
{
MyClass a;
a.my_func();
}
// f2.cpp
#include "my_class.h"
void f2()
{
MyClass a;
a.my_func();
}
// main.cpp
#include "f.h"
int main()
{
f1();
f2();
return 0;
}
I tried to compile this code with
$ g++ f1.cpp f2.cpp main.cpp
Obviously, the linker complained of duplicate symbol my_func
:
duplicate symbol __ZN7MyClass7my_funcEv in:
/var/folders/yj/zz96q16j6vd1dq1_r3mz8hzh0000gn/T/f1-962ae7.o
/var/folders/yj/zz96q16j6vd1dq1_r3mz8hzh0000gn/T/f2-aef78c.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
The next attempt I had was to move the function definition inside the class definition, so we get:
struct MyClass
{
void my_func()
{}
};
Running the same g++
command, the program compiles successfully. This is because functions defined in class definition are implicitly marked inline
(§10.1.6 * 3).
The standard states:
A function declaration (11.3.5, 12.2.1, 14.3) with an inline specifier declares an inline function. The inline specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. An implementation is not required to perform this inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules for inline functions specified in this section shall still be respected
Which seems somewhat in contradiction to what is written on cppreference.com:
Because the meaning of the keyword inline for functions came to mean "multiple definitions are permitted" rather than "inlining is preferred", [...]
So as far as I understand, having a function defined in the class definition makes it implicitly inline
which does not necessarily mean that the compiler will choose to inline its body but will a definition of it in every translation unit. Is this correct?
The second question comes regarding template classes. Separating the declaration/definition of a template class is a problem, as described here so we can only have function definitions in the class definition which makes it implicitly inline
, again, right? What is the impact of this?
Since we only have the choice of defining functions in class definitions when the class is a template, what is to be done about classes that are not template? Should we define function in source files and only keep the declaration in headers when possible?