Let's say:
Some header h.hpp defines a template function f() using sizeof on its template parameter.
Two different C++ source files, a.cpp and b.cpp, define their own structure having the same name S.
Both a.cpp and b.cpp use f() with their own S.
In other words:
h.hpp:
template <typename T>
int f()
{
return something + sizeof(T);
}
a.cpp:
#include "h.hpp"
struct S {
int a;
int b;
};
int aFunc()
{
return f<S>();
}
b.cpp:
#include "h.hpp"
struct S {
int w;
int x;
int y;
int z;
};
int bFunc()
{
return f<S>();
}
Here, within the same program, both aFunc() and bFunc() return the same value. This is because both structures are named S, and only one template function instantiation is kept.
My working solutions so far are:
Name the structures differently.
Make f() static.
Make f() part of an anonymous namespace.
Make both structures part of their own anonymous namespace.
Can you think of anything else to avoid this issue which only manifests at run time?
I need to end this.
Considering the comments of n. 1.8e9-where's-my-share m. and VainMan: such a program is indeed ill-formed (ODR violation).
Therefore, the only legal solutions are those (1 and 4):
Name the structures differently.
Make both structures part of their own anonymous namespace.
I somehow stopped reading the One Definition Rule section at:
There can be more than one definition in a program of each of the following: class type, enumeration type, inline function, inline variable (since C++17), templated entity (template or member of template, but not full template specialization), as long as all of the following is true:
each definition appears in a different translation unit
But there's another important condition:
each definition consists of the same sequence of tokens (typically, appears in the same header file)
This is obviously not my case.
The outcome of not satisfying any of those conditions is:
Otherwise, the program is ill-formed, no diagnostic required.
Related
I have been programming in C++ for quite some time and I never thought about this until today.
Consider the following code:
struct foo
{
// compiles fine
void bar()
{
a = 1;
my_int_type b;
b = 5;
}
// Just a declaration, this fails to compile, which leads me to assume that
// even though the bar() method is declared and defined all at once, the
// compiler looks/checks-syntax-of the class interface first, and then compiles
// the respective definitions...?
void bar2(my_int_type); // COMPILE ERROR
my_int_type b; // COMPILE ERROR because it comes before the typedef declaration
typedef int my_int_type;
my_int_type a;
void bar3(my_int_type); // compiles fine
};
int main()
{
foo a;
a.bar();
return 0;
}
Is my understanding of why the errors occur (see bar2() comment above) correct/incorrect? Either way, I would appreciate an answer with a simplistic overview of how a single-pass C++ compiler would compile the code given above.
For the most part, a C++ file is parsed top-to-bottom, so entities must be declared before they are used.
In your class, bar2 and b are invalid because they both make use of my_int_type, which has not yet been declared.
One exception to the "top-to-bottom" parsing rule is member functions that are defined inside the definition of their class. When such a member function definition is parsed, it is parsed as if it appeared after the definition of the class. This is why your usage of my_int_type in bar is valid.
Effectively, this:
struct foo
{
void bar()
{
my_int_type b;
}
typedef int my_int_type;
};
is the same as:
struct foo
{
void bar();
typedef int my_int_type;
};
inline void foo::bar()
{
my_int_type b;
}
Compiler just starts to go down in a block. Any symbol which is not familiar to it will be considered as a new symbol which is not defined. This is the scheme behind the function definition or header files.
You can suppose that the compiler first makes a list of definitions so the bar() method should get compiled correctly because the definitions have provided before.
It has a lot to do with visibility. I think your confusion may come from assuming a single pass. Think of class parsing as done in two stages.
Parse class definition.
Parse method implementation.
The advantage to this is we have visibility of the entire class from within class member functions.
The access to members of a template base class requires the syntax this->member or the using directive. Does this syntax extends also to base template classes which are not directly inherited?
Consider the following code:
template <bool X>
struct A {
int x;
};
template <bool X>
struct B : public A<X> {
using A<X>::x; // OK even if this is commented out
};
template <bool X>
struct C : public B<X> {
// using B<X>::x; // OK
using A<X>::x; // Why OK?
C() { x = 1; }
};
int main()
{
C<true> a;
return 0;
}
Since the declaration of the template class B contains using A<X>::x, naturally the derived template class C can access to x with a using B<X>::x. Nevertheless, on g++ 8.2.1 and clang++ 6.0.1 the above code compiles fine, where x is accessed in C with a using that picks up x directly from A
I would have expected that C can not access directly to A. Also, commenting out the using A<X>::x in B still makes the code to compile. Even the combination of commenting out using A<X>::x in B and at the same time employ in C using B<X>::x instead of using A<X>::x gives a code that compiles.
Is the code legal?
Addition
To be more clear: the question arises on template classes and it is about the visibility of members inherited by template classes.
By standard public inheritance, the public members of A are accessible to C, so using the syntax this->x in C one does indeed get access to A<X>::x. But what about the using directive? How does the compiler correctly resolve the using A<X>::x if A<X> is not a direct base of C?
You are using A<X> where a base class is expected.
[namespace.udecl]
3 In a using-declaration used as a member-declaration, each
using-declarator's nested-name-specifier shall name a base class of
the class being defined.
Since this appears where a class type is expected, it is known and assumed to be a type. And it is a type that is dependent on the template arguments, so it's not looked up immediately.
[temp.res]
9 When looking for the declaration of a name used in a template
definition, the usual lookup rules ([basic.lookup.unqual],
[basic.lookup.argdep]) are used for non-dependent names. The lookup of
names dependent on the template parameters is postponed until the
actual template argument is known ([temp.dep]).
So it's allowed on account of the compiler not being able to know any better. It will check the using declaration when the class is instantiated. Indeed, one can put any dependent type there:
template<bool> struct D{};
template <bool X>
struct C : public B<X> {
using D<X>::x;
C() { x = 1; }
};
This will not be checked until the value of X is known. Because B<X> can bring with it all sorts of surprises if it's specialized. One could for instance do this:
template<>
struct D<true> { char x; };
template<>
struct B<true> : D<true> {};
Making the above declaration be correct.
Is the code legal?
Yes. This is what public inheritance does.
Is it possible to allow a template class derived from B to access to x only via this->x, using B::x or B::x? ...
You can use private inheritance (i.e. struct B : private A<X>), and arrange access to A<X>::x only through B's public/protected interface.
Also, if you're worried about having hidden members, you should use class instead of struct and specify the desired visibility explicitly.
Regarding the addition, note that:
(1) the compiler knows what object A<X>::x refers to given some instance of A<X> (because A is defined in the global scope, and X is the template parameter of C).
(2) You do indeed have an instance of A<X> - this is a ponter to a derived class (it doesn't matter if A<X> is a direct base class or not).
(3) The object A<X>::x is visible in the current scope (because the inheritances and the object itself are public).
The using statement is merely syntactic sugar. Once all types are resolved, the compiler replaces following use of x with the appropriate memory address in the instance, not unlike writing this->x directly.
Maybe this example could give you some idea as to why should it be legal:
template <bool X>
struct A {
int x;
};
template <bool X>
struct B : public A<X> {
int x;
};
template <bool X>
struct C : public B<X> {
//it won't work without this
using A<X>::x;
//or
//using B<X>::x;
C() { x = 1; }
// or
//C() { this -> template x = 1; }
//C() { this -> x = 1; }
};
In case of choosing C() { this -> template x = 1; } the last inherited x (B::x) would be assigned to 1 not the A::x.
It can simply be tested by:
C<false> a;
std::cout << a.x <<std::endl;
std::cout << a.A::x <<std::endl;
std::cout << a.B::x <<std::endl;
Assuming that the programmer for struct B was not aware of struct A members, but the programmer of struct c was aware of members of both, it seems very reasonable for this feature to be allowed!
As to why should compiler be able to recognize using A<X>::x; when it is used in C<X> , consider the fact that within the definition of a class/class template all the direct/indirect inherited bases are visible regardless of the type of inheritance. But only the publicly inherited ones are accessible!
For example if it was like:
using A<true>::x;
//or
//using B<true>::x;
Then there would be a problem by doing:
C<false> a;
Or wise versa. since neither A<true> or B<true> is a base for C<false>, therefor visible. But since it is like:
using A<X>::x;
Because the generic term X is used in order to define the term A<X>, it is first deducible second recognizable, since any C<X> (if is not specialized later) is indirectly based on A<X> !
Good Luck!
template <bool X>
struct C : public B<X> {
// using B<X>::x; // OK
using A<X>::x; // Why OK?
C() { x = 1; }
};
The question is why wouldn't that be supported? Because the constrain that A<X> is a base of a specialization of the main template definition of C is a question that can only be answered, and that only makes sense for a particular template argument X?
To be able to check templates at definition time was never a design goal of C++. Many well formed-ness constrains are checked at instanciation time and this is fine.
[Without a true concept (necessary and sufficient template parameter contracts) support no variant of C++ would do significantly better, and C++ is probably too complicated and irregular to have true concepts and true separate checking of templates, ever.]
The principles that makes it necessary to qualify a name to make it dependent does not have anything with early diagnostic of errors in template code; the way name lookup works in template was considered necessary by the designers to support "sane" (actually slightly less insane) name lookup in template code: a use of a non local name in a template shouldn't bind too often to a name declared by the client code, as it would break encapsulation and locality.
Note that for any unqualified dependent name you can end up accidentally calling an unrelated clashing user function if it's a better match for overloading resolution, which is another problem that would be fixed by true concept contracts.
Consider this "system" (i.e. not part of current project) header:
// useful_lib.hh _________________
#include <basic_tool.hh>
namespace useful_lib {
template <typename T>
void foo(T x) { ... }
template <typename T>
void bar(T x) {
...foo(x)... // intends to call useful_lib::foo(T)
// or basic_tool::foo(T) for specific T
}
} // useful_lib
And that project code:
// user_type.hh _________________
struct UserType {};
// use_bar1.cc _________________
#include <useful_lib.hh>
#include "user_type.hh"
void foo(UserType); // unrelated with basic_tool::foo
void use_bar1() {
bar(UserType());
}
// use_bar2.cc _________________
#include <useful_lib.hh>
#include "user_type.hh"
void use_bar2() {
bar(UserType()); // ends up calling basic_tool::foo(UserType)
}
void foo(UserType) {}
I think that code is pretty realistic and reasonable; see if you can see the very serious and non local issue (an issue that can only be found by reading two or more distinct functions).
The issue is caused by the use of an unqualified dependent name in a library template code with a name that isn't documented (intuitivement shouldn't have to be) or that is documented but that the user wasn't interested in, as he never needed to override that part of the library behavior.
void use_bar1() {
bar(UserType()); // ends up calling ::foo(UserType)
}
That wasn't intended and the user function might have a completely different behavior and fails at runtime. Of course it could also have an incompatible return type and fail for that reason (if the library function returned a value unlike in that example, obviously). Or it could create an ambiguity during overload resolution (more involved case possible if the function takes multiple arguments and both library and user functions are templates).
If this wasn't bad enough, now consider linking use_bar1.cc and use_bar2.cc; now we have two uses of the same template function in different contexts, leading to different expansions (in macro-speak, as templates are only slightly better than glorified macros); unlike preprocessor macros, you are not allowed to do that as the same concrete function bar(UserType) is being defined in two different ways by two translation units: this is an ODR violation, the program is ill formed no diagnostic required. That means that if the implementation doesn't catch the error at link time (and very few do), the behavior at runtime is undefined from start: no run of the program has defined behavior.
If you are interested, the design of name lookup in template, in the era of the "ARM" (Annotated C++ Reference Manual), long before ISO standardization, is discussed in D&E (Design and Evolution of C++).
Such unintentional binding of a name was avoided at least with qualified names and non dependent names. You can't reproduce that issue with a non dependent unqualified names:
namespace useful_lib {
template <typename T>
void foo(T x) { ... }
template <typename T>
void bar(T x) {
...foo(1)... // intends to call useful_lib::foo<int>(int)
}
} // useful_lib
Here the name binding is done such that no better overload match (that is no match by a non template function) can "beat" the specialization useful_lib::foo<int> because the name is bound in the context of the template function definition, and also because useful_lib::foo hides any outside name.
Note that without the useful_lib namespace, another foo that happened to be declared in another header included before could still be found:
// some_lib.hh _________________
template <typename T>
void foo(T x) { }
template <typename T>
void bar(T x) {
...foo(1)... // intends to call ::foo<int>(int)
}
// some_other_lib.hh _________________
void foo(int);
// user1.cc _________________
#include <some_lib.hh>
#include <some_other_lib.hh>
void user1() {
bar(1L);
}
// user2.cc _________________
#include <some_other_lib.hh>
#include <some_lib.hh>
void user2() {
bar(2L);
}
You can see that the only declarative difference between the TUs is the order of inclusion of headers:
user1 causes the instanciation of bar<long> defined without foo(int) visible and name lookup of foo only finds the template <typename T> foo(T) signature so binding is obviously done to that function template;
user2 causes the instanciation of bar<long> defined with foo(int) visible so name lookup finds both foo and the non template one is a better match; the intuitive rule of overloading is that anything (function template or regular function) that can match less argument lists wins: foo(int) can only match exactly an int while template <typename T> foo(T) can match anything (that can be copied).
So again the linking of both TUs causes an ODR violation; the most likely practical behavior is that which function is included in the executable is unpredictable, but an optimizing compiler might assume that the call in user1() does not call foo(int) and generate a non inline call to bar<long> that happens to be the second instanciation that ends up calling foo(int), which might cause incorrect code to be generated [assume foo(int) could only recurse through user1() and the compiler sees it doesn't recurse and compile it such that recursion is broken (this can be the case if there is a modified static variable in that function and the compiler moves modifications across function calls to fold successive modifications)].
This shows that templates are horribly weak and brittle and should be used with extreme care.
But in your case, there is no such name binding issue, as in that context a using declaration can only name a (direct or indirect) base class. It doesn't matter that the compiler cannot know at definition time whether it's a direct or indirect base or an error; it will check that in due time.
While early diagnostic of inherently erroneous code is permitted (because sizeof(T()) is exactly the same as sizeof(T), the declared type of s is illegal in any instantiation):
template <typename T>
void foo() { // template definition is ill formed
int s[sizeof(T) - sizeof(T())]; // ill formed
}
diagnosing that at template definition time is not practically important and not required for conforming compilers (and I don't believe compiler writers try to do it).
Diagnostic only at the point of instantiation of issues that are guaranteed to be caught at that point is fine; it does not break any design goal of C++.
I understand the use of unnamed namespaces to make functions and variables have internal linkage. Unnamed namespaces are not used in header files; only source files. Types declared in a source file cannot be used outside. So what's the use of putting types in unnamed namespaces?
See these links where it's mentioned that types can be put in unnamed namespaces:
Superiority of unnamed namespace over static?
Unnamed/anonymous namespaces vs. static functions
Why an unnamed namespace is a "superior" alternative to static?
Where do you want to put local types other than the unnamed namespace? Types can't have a linkage specifier like static. If they are not publicly known, e.g., because they are declared in a header, there is a fair chance that names of local types conflict, e.g., when two translation units define types with the same name. In that case you'd end up with an ODR violation. Defining the types inside an unnamed namespace eliminates this possibility.
To be a bit more concrete. Consider you have
// file demo.h
int foo();
double bar();
// file foo.cpp
struct helper { int i; };
int foo() { helper h{}; return h.i; }
// file bar.cpp
struct helper { double d; }
double bar() { helper h{}; return h.d; }
// file main.cpp
#include "demo.h"
int main() {
return foo() + bar();
}
If you link these three translation units, you have mismatching definitions of helper from foo.cpp and bar.cpp. The compiler/linker is not required to detect these but each type which is used in the program needs to have a consistent definition. Violating this constraints is known as violation of the "one definition rule" (ODR). Any violation of the ODR rule results in undefined behavior.
Given the comment it seems a bit more convincing is needed. The relevant section of the standard is 3.2 [basic.def.odr] paragraph 6:
There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member
of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then each definition of D shall consist of the same sequence of tokens; and
[...]
There are plenty of further constraints but "shall consist of the same sequence of tokens" is clearly sufficient to rule out e.g. the definitions in the demo above from being legal.
So what's the use of putting types in unnamed namespaces?
You can create short, meaningful classes with names that maybe used in more than one file without the problem of name conflicts.
For example, I use two classes often in unnamed namespaces - Initializer and Helper.
namespace
{
struct Initializer
{
Initializer()
{
// Take care of things that need to be initialized at static
// initialization time.
}
};
struct Helper
{
// Provide functions that are useful for the implementation
// but not exposed to the users of the main interface.
};
// Take care of things that need to be initialized at static
// initialization time.
Initializer initializer;
}
I can repeat this pattern of code in as many files as I want without the names Initializer and Helper getting in the way.
Update, in response to comment by OP
file-1.cpp:
struct Initializer
{
Initializer();
};
Initializer::Initializer()
{
}
int main()
{
Initializer init;
}
file-2.cpp:
struct Initializer
{
Initializer();
};
Initializer::Initializer()
{
}
Command to build:
g++ file-1.cpp file-2.cpp
I get linker error message about multiple definitions of Initializer::Initializer(). Please note that the standard does not require the linker to produce this error. From section 3.2/4:
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required.
The linker does not produce an error if the functions are defined inline:
struct Initializer
{
Initializer() {}
};
That's OK for a simple case like this since the implementations are identical. If the inline implementations are different, the program is subject to undefined behavior.
I might be a bit late for answering the question the OP made but since I think the answer is not fully clear, I would like to help future readers.
Lets try a test... compile the following files:
//main.cpp
#include <iostream>
#include "test.hpp"
class Test {
public:
void talk() {
std::cout<<"I'm test MAIN\n";
}
};
int main()
{
Test t;
t.talk();
testfunc();
}
//test.hpp
void testfunc();
//test.cpp
#include <iostream>
class Test {
public:
void talk()
{
std::cout<<"I'm test 2\n";
}
};
void testfunc() {
Test t;
t.talk();
}
Now run the executable.
You would expect to see:
I'm test MAIN
I'm test 2
What you should see thought is:
I'm test MAIN
I'm test MAIN
What happened?!?!!
Now try putting an unnamed namespace around the "Test" class in "test.cpp" like so:
#include <iostream>
#include "test.hpp"
namespace{
class Test {
public:
void talk()
{
std::cout<<"I'm test 2\n";
}
};
}
void testfunc() {
Test t;
t.talk();
}
Compile it again and run.
The output should be:
I'm test MAIN
I'm test 2
Wow! It works!
As it turns out, it is important to define classes inside unnamed namespaces so that you get the proper functionality out of them when two class names in different translation units are identical.
Now as to why that is the case, I haven't done any research on it (maybe someone could help here?) and so I can't really tell you for sure. I'm answering purely from a practical standpoint.
What I would suspect though is that, while it is true that C structs are indeed local to a translation unit, they are a bit different from classes since classes in c++ usually have behavior assigned to them. Behavior means functions and as we know, functions are not local to the translation unit.
This is just my assumption.
Within the same compilation unit, the C++ standard says that static initialization order is well defined -- it's the order of the declarations of the static objects. But using the Sun Studio 12 compiler I'm encountering unintuitive behavior. I've define a templated class helper<T> which contains a static member _data of type T and a static member function that uses _data called foo. In my .cpp file I have this above main():
struct A { /* some definition */ };
typedef helper<int> s0;
typedef helper<A> s1;
Notice that the typedef for helper<int> comes before the typedef for helper<A>. Thus according to the standard I would expect that helper<int>::_data will be constructed before helper<A>::_data (remember _data is a static member). On GCC this is the case, on Sun it is not.
This is problematic because A's constructor uses helper<int>::_data. I only have one compilation unit, with no earlier potential instantiation of helper<A>, so I thought the order should be well defined. Is this a Sun compiler bug, or does the typedef not constitute a definition/instantiation technically? What I mean is, is the Sun compiler's behavior allowed by the standard?
I have the following main():
int main()
{
//Swapping the order of these has no effect on Sun
s0::foo();
s1::foo();
}
There are no other uses of s0 or s1.
Within the same compilation unit, the C++ standard says that static initialization order is well defined -- it's the order of the declarations of the static objects.
In your shown code you have no declaration of a static data member. You have a declaration of a typedef-name. These have nothing to do with that, and don't influence any order. You probably think along this way:
If i make that typedef declaration, it will instantiate helper<int>, and thus instantiate its static data member declaration first.
The problem is, that line does not cause an instantiation of helper<int>. For that to happen, you would need an explicit instantiation or manage to make it instantiate it implicitly (creating an object of helper<int> for example, or using it as a nested name specifier as in helper<int>::... and explicitly referencing the static member - otherwise, creation of it is omitted).
But there is a much deeper problem. The order is not the declaration of the static data-members. The order is their definition. Consider the following
struct C { C() { printf("hey\n"); } };
struct A {
static C a;
static C b;
};
C A::b;
C A::a;
In this code, b is created before a, even though a is declared before b.
The following code prints 2 1:
struct C { C(int n) { printf("%d\n", n); } };
template<int N>
struct A {
static C c;
};
template<int N>
C A<N>::c(N);
// explicit instantiation of declaration and definition
template struct A<2>;
template struct A<1>;
int main() {
}
But the following code prints nothing, unless you comment in the line in main.
struct C { C(int n) { printf("%d\n", n); } };
template<int N>
struct A {
static C c;
};
template<int N>
C A<N>::c(N);
// implicit instantiation of declarations
A<2> a2;
A<1> a1;
int main() {
// A<1>::c; A<2>::c;
}
I'm not actually sure what the correct output for this second snippet is. Reading the Standard, i can't determine an order. It says at 14.6.4.1 "Point of Instantiation":
For a function template specialization, a member function template specialization, or a specialization for a member function or static data member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization [...]. Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization.
The point of instantiation of their definitions both appear immediately after the definition of main. Which definition is instantiated before the other definition seems to be left unspecified. If anyone knows the answer and khow other compilers behave (GCC prints 1 2 but with the order of the expressions in main swapped, prints 2 1), please let me know in the comment.
For details, see this answer about static object's lifetime.
You're not actually declaring any objects in that code.
You need extra code:
s0 one;
s1 two;
In that case, the two objects are now actually declared, and should work correctly.
Are you explicitly declaring a s0?
Try following the typedefs with a s0 dummy; and see if the problem is resolved.
I have a template class defined in a header file like this. Here I have defined a static variable as well:
#ifndef TEST1_H_
#define TEST1_H_
void f1();
static int count;
template <class T>
class MyClass
{
public:
void f()
{
++count;
}
};
#endif
And I have defined main() function in a different cpp file like this:
int main(int argc, char* argv[])
{
MyClass<int> a;
a.f();
f1();
cout<<"Main:" << count << "\n";
return 0;
}
I have implemented function f1() in a different cpp file like this:
void f1()
{
MyClass<int> a;
a.f();
cout<<"F1: " <<count <<"\n";
}
When I compiled this using VC6, I got the output as "F1:0 Main:2". How is this possible? Also, in general how should I handle if I want to use static variables along with templates?
You're getting two copies of the same variable because you've declared a static variable in a header file. When you declare a global variable static this way, you're saying it's local to the compilation unit (the .o file). Since you include the header in two compilation units, you get two copies of count.
I think what you really want here is a static template member variable associated with each instance of the template class. It would look like this:
template <class T>
class MyClass
{
// static member declaration
static int count;
...
};
// static member definition
template<class T> int MyClass<T>::count = 0;
This will get you a count for each instantiation of your template. That is, you'll have a count for MyClass<int>, MyClass<foo>, MyClass<bar>, etc. f1() would now look like this:
void f1() {
MyClass<int> a;
a.f();
cout<<"F1: " << MyClass<int>::count <<"\n";
}
If you want a count for all instantiations of MyClass (regardless of their template parameters), you do need to use a global variable.
However, you probably don't want a global variable directly because you run the risk of using it before it gets initialized. You can get around this by making a global static method that returns a reference to your count:
int& my_count() {
static int count = 0;
return count;
}
Then accessing it from within your class like this:
void f() {
++my_count();
}
This will ensure that count gets initialized before it's used, regardless of which compilation unit you access it from. See the C++ FAQ on static initialization order for more details.
Putting the static declaration in a header file will cause each .cpp file to get its own version of the variable. So the two cout statements are printing different variables.
Were you expecting "F1:1 Main:1"? You instantiated MyClass<int> in two separate translation units (i.e. two object files), and the linker saw that there was a duplicate template instantiation, so it discarded the instantiation that was in f1's object file.
Are you passing /OPT:ICF or /OPT:REF to the VC6 linker? That might be related to the duplicate template instantiation removal (or not; duplicate template instantiations might be a special case, compared to ordinary duplicate functions). GCC seems to do something similar on some platforms.
Anyway, I wouldn't rely on this behavior being consistent across compilers. Also, changing the order of object files on the linker command line might affect which instantiation gets discarded.
There is another solution, you can create a shared parent class and put this static variable in it, then make your template class inherit it privately, here's an example:
class Parent
{
protected:
static long count;
};
long Parent::count = 0;
template<typename T>
class TemplateClass: private Parent
{
private:
int mKey;
public:
TemplateClass():mKey(count++){}
long getKey(){return mKey;}
}
int main()
{
TemplateClass<int> obj1;
TemplateClass<double> obj2;
std::cout<<"Object 1 key is: "<<obj1.getKey()<<std::endl;
std::cout<<"Object 2 key is: "<<obj2.getKey()<<std::endl;
return 0;
}
Output will be:
Object 1 key is: 0
Object 2 key is: 1
I think this is actually undefined behaviour.
According to C++14 [basic.def.odr]/6:
There can be more than one definition of a [...] member function of a class template [...] in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then
each definition of D shall consist of the same sequence of tokens; and
in each definition of D, corresponding names, looked up according to 3.4, shall refer to an entity defined within the definition of D, or shall refer to the same entity, after overload resolution (13.3) and after matching of partial template specialization (14.8.3), except that a name can refer to a non-volatile
const object with internal or no linkage if the object has the same literal type in all definitions of D, and the object is initialized with a constant expression (5.19), and the object is not odr-used, and the object has the same value in all definitions of D; [...]
The problem is that in the first .cpp file, the name count within f1 refers to a different object than the name count within f1 in the second .cpp file, thus violating the condition that corresponding names should refer to the same entity.
They are different objects because of the static specifier which says that each translation unit gets its own object with that name.