Suppose I have a header only library. I have simplified it to something like this.
Header only library Foo.hpp
#ifndef FOO_HPP
#define FOO_HPP
struct Foo{
static const int A;
};
const int Foo::A = 100;
void SomeMethod(){
// do some stuff
}
#endif
Then, I have parent class (Parent.hpp
and Parent.cpp
):
#ifndef PARENT_HPP
#define PARENT_HPP
#include "Foo.hpp"
struct Parent {
virtual void my_method();
};
#endif
Child class (Child.hpp
and Child.cpp
)
#ifndef CHILD_HPP
#define CHILD_HPP
#include "Parent.hpp"
#include "Foo.hpp"
struct Child : Parent{
void my_method();
};
#endif
In my_method()
, I just print the Foo::A
variable.
In the real code base, I have template in the header only library.
When I compile this, I got a "multiple definition" error. How to fix this?
You have chosen the "non-inline" mode of initializing your static member. That is perfectly legitimate, but - in this case, you need to have exactly one translation unit (e.g. compiled .cpp
file) defining your member. Otherwise, the C++ linker sees one definition of Foo::A
in parent.o
and a second definition in child.o
, and those conflict.
Thus,
Foo.cpp
, which includes Foo.hpp
and defines Foo::A
.This is not really recommended, but it does work.
Surround the definition like so:
#ifdef FOO_A_DEFINITION
const int Foo::A = 100;
#endif
Create a Foo.cpp
, which defines #FOO_A_DEFINITION
and then includes Foo.hpp
This has the detriment of using macros, but the benefit of human users seeing the definition from the header.
So, you are asking yourself "Why should they conflict? I want the compiler to know that they're the same variable!"
One way to do this to initialize the static member within the class body. Since this is a simple type, that's possible even with older versions of the language standard. This is also @idmean's suggested solution:
class Foo {
public:
static const int A = 100;
};
There's a caveat here, which is that you're "not really" defining the static member this way. You can use it, but not in every way you would use a variable defined with solutions (1.) or (2.). See discussion here:
See a discussion of this point here:
Defining static const integer members in class definition
This solution is another way to tell the compiler "it's just one definition for everybody", which only works in C++17 or later:
#include <iostream>
class Foo {
public:
inline static const int A = 100;
};
This looks very similar to Solution 3, but actually does something very different!
With this solution, you're actually defining the static member multiple times - in each translation unit - but are telling the compiler to only keep a single definition when linking and encountering many of them.
Solutions (1.) and (2.) behave differently from this solution (4.) when you use dynamically-linked libraries. See:
Where to initialize static const member in c++17 or newer?
for an explanation.