开发者

How do explicit template instantiations affect what the linker can find?

See the following code and please clear my doubts.

  1. 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?

  2. 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜