How do explicit template instantiations affect what the linker can find?
See the following code and please clear my doubts.
As ABC is a template, why does it not show an error when we put the definition of the ABC class member function in test.cpp?
If I put test.cpp code in test.h and remve 2, then it works fine. Why?
.
// test.h
templat开发者_运维知识库e <typename T>
class ABC {
public:
void foo( T& );
void bar( T& );
};
// test.cpp
template <typename T>
void ABC<T>::foo( T& ) {} // definition
template <typename T>
void ABC<T>::bar( T& ) {} // definition
template void ABC<char>::foo( char & ); // 1
template class ABC<char>; // 2
// main.cpp
#include "test.h"
int main() {
ABC<char> a;
a.foo(); // valid with 1 or 2
a.bar(); // link error if only 1, valid with 2
}
In both cases you are doing an explicit instantiation. In the second case, only ABC<char>::foo
is being instantiated, while in the first case ABC<char>::bar
is also being instantiated.
A different similar example may clarify the implications:
// test.h
template <typename T>
class ABC {
public:
void foo( T& );
void bar( T& );
};
// test.cpp
template <typename T>
void ABC<T>::foo( T& ) {} // definition
template <typename T>
void ABC<T>::bar( T& ) {} // definition
template void ABC<char>::foo( char & ); // 1
template class ABC<char>; // 2
// main.cpp
#include "test.h"
int main() {
ABC<char> a;
a.foo(); // valid with 1 or 2
a.bar(); // link error if only 1, valid with 2
}
In the example, in main
the compiler cannot see foo
nor bar
definitions, so it cannot instantiate the methods. The compiler, when processing main.cpp will accept the code in main gladly, since you are telling it that ABC
is a template and that it has those two functions, and will assume that they will be defined in some other translation unit.
In the translation unit that contains test.cpp the compiler is seeing both method definitions, and the both of the instantiations (method/class) can be fully processed. If only the method instantiation ([1]) is present, the compiler will only generate that method, and will leave bar
undefined. So any code that includes test.h, links against the compiled test.cpp and uses only foo
method will compile and link, but usage of bar
will fail to link due to it being undefined.
Explicitly instantiating the class template generates the symbols for all the member methods, and in that case, any translation unit that includes test.h and links against the compiled test.cpp object file will both compile and link.
(This is an edited version of my original answer, prompted by David Rodriguez's observation.)
#1
instantiates the class template, and as part of that instantiates all its methods.
#2
instantiates one member method of the class. As part of that it has to instantiate the class template, but not all its other methods.
The difference can be seen if you introduce a type-dependent error into bar() (e.g. a statement like void *x = b;
). You'll get a compiler error with #1
but not with #2
. Also note that the compiler (gcc at least) would not compile #1
followed by #2
, but would compile either of them without the other, or if #2
were followed by #1
.
I guess you wanted to have {} instead of ; in #1.
精彩评论