a.hpp:
#pragma once
struct S
{
static int v;
};
int S::v = 0;
b.hpp:
#pragma once
void addOne();
b.cpp:
#include "b.hpp"
#include "a.hpp"
void addOne()
{
S::v += 1;
}
main.cpp:
#include <iostream>
#include "a.hpp"
#include "b.hpp"
int main()
{
S::v = 2;
addOne();
S::v += 2;
std::cout << S::v << std::endl;
}
Does not work when compiling with g++ -std=c++14 main.cpp b.cpp && ./a.out
(multiple definition of S::v).
However when I change the code to: a.hpp:
#pragma once
struct S
{
template<typename T>
static int v;
};
template<typename T>
int S::v = 0;
and replace all S::v
with S::v<void>
it compiles and works how I intended the first example to work (outputs 5
).
I believe I know why the first code example does not work: The int S::v = 0;
line gets once compiled in the main.cpp
unit and once in the b.cpp
unit. When the linker links these two together, then the variable S::v
gets essentially redefined.(?)
Why does the code with the template work?
Why does the code with the template work?
Essentially, because the standard says so.
With templates, the rules usually amoun to: "everyone using them must have their definition available." The exact same applies to static data members of class templates: a definition of such a static data member must be present in every translation unit in which it is odr-used. It's up to the compiler & linker to make sure this does not lead to errors.
Note that since C++17, you can solve the non-template case by making the static data member inline:
#pragma once
struct S
{
static inline int v = 0;
};
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