That code will give you multiple instances of AirplaneDataProxy<AirplaneData>::instance. One for each .cpp file that compiles it. It isn't quite the right solution. |
I'm pretty sure that's not true. It doesn't happen on my machine.
Once instantiated, only one instance of a templated class is used. If one cpp file instantiates Foo<int>, then Foo<int> is externally linked like any other normal non-templated class and other cpp files can reference it.
Here's a trivial program I made to test:
1 2 3 4 5 6 7 8 9 10 11
|
// header.h
void IncrementT();
template <typename T>
class Foo
{
public:
static T t;
};
template <typename T> T Foo<T>::t = 0;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
// main.cpp
#include <iostream>
#include "header.h"
int main()
{
std::cout << Foo<int>::t << "\n"; // prints 0 as you'd expect
IncrementT();
std::cout << Foo<int>::t << "\n"; // prints 1 as you'd expect
char ch;
std::cin >> ch;
return 0;
}
|
1 2 3 4 5 6 7 8
|
// file2.cpp
#include "header.h"
void IncrementT()
{
Foo<int>::t += 1;
}
|
Foo<int> is being instantiated in both main.cpp and file2.cpp. Yet changes made to the static member 't' in one file2.cpp are visible in main.cpp, proving that the cpp files are sharing the same instance.
EDIT:
gabriele82rm wrote: |
---|
In many forums static members definition in header files is strongly deprecated to avoid this problem. Am I wrong? |
Templates don't follow "normal" rules that way (and that's not really "deprecated" as much as it's "not legal" -- try it and you'll likely get linker errors)
Remember that 'Foo' is not a class, it's a template. Foo<int> is the class.
If multiple cpp files instantiate the same class, then the linker will only use one of them, and the others are quietly "dropped". This has other hidden dangers (See below) which is why it's not allowed for normal non-templated classes... but it is a necessary evil in order to make templates work this way. The alternatives are much worse.
As for the dangers of this behavior... it allows for the possibility of functions with the same name but different bodies to be produced without error. Resulting in one of them being quietly "dropped" leading to potentially unexpected behavior.
Here's an example:
1 2 3 4 5 6 7 8 9 10
|
//header.h
template <typename T>
class Foo
{
public:
void print() const;
};
void CallFile1(const Foo<int>& v);
void CallFile2(const Foo<int>& v);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
// file1.cpp
#include "header.h"
#include <iostream>
template <typename T>
void Foo<T>::print() const
{
std::cout << "Calling from file1\n";
}
void CallFile1(const Foo<int>& v)
{
v.print();
}
int main()
{
Foo<int> a;
CallFile1(a);
CallFile2(a);
return 0;
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
// file2.cpp
#include "header.h"
#include <iostream>
template <typename T>
void Foo<T>::print() const
{
std::cout << "Calling from file2\n";
}
void CallFile2(const Foo<int>& v)
{
v.print();
}
|
Notice that both cpp files define their own Foo<T>::print function. Yet there's no linker error.
Also note that only one of them will be called. Which one is called depends entirely on which instantiation the linker decides to keep (ie: flip a coin, phase of the moon, etc)