显式模板实例化如何影响链接器无法找到的内容?

时间:2010-04-29 07:17:34

标签: c++ templates

请参阅以下代码,请清除我的疑问。

  1. 由于ABC是一个模板,为什么在将我的ABC类成员函数的定义放在test.cpp中时它不显示错误?

  2. 如果我将test.cpp代码放在test.h中并重新启动2,那么它可以正常工作。为什么呢?

  3. // 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 
    } 
    

3 个答案:

答案 0 :(得分:13)

在这两种情况下,您都在进行显式实例化。在第二种情况下,只有ABC<char>::foo被实例化,而在第一种情况下,ABC<char>::bar也被实例化。

另一个类似的例子可能会澄清其含义:

// 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
}

在示例中,在main中,编译器无法查看foobar定义,因此无法实例化方法。编译器在处理main.cpp时会很乐意接受main中的代码,因为你告诉它ABC是一个模板并且它有这两个函数,并假设它们将在其他一些翻译中定义单元。

在包含test.cpp的转换单元中,编译器会看到两个方法定义,并且可以完全处理这两个实例(方法/类)。如果仅存在方法实例化([1]),则编译器将仅生成该方法,并且将bar保留为未定义。因此,任何包含test.h的代码,针对已编译的test.cpp的链接以及仅使用foo方法的代码都将进行编译和链接,但bar的使用将由于未定义而无法链接。

显式地实例化类模板会为所有成员方法生成符号,在这种情况下,任何包含test.h的翻译单元和编译的test.cpp对象文件的链接都将编译和链接。

答案 1 :(得分:0)

(这是我的原始答案的编辑版本,由David Rodriguez的观察提示。)

#1实例化类模板,并将其实例化所有方法。

#2实例化该类的一个成员方法。作为其中的一部分,它必须实例化类模板,但不是所有其他方法。

如果将类型相关的错误引入bar()(例如void *x = b;之类的语句),则可以看出差异。使用#1时会出现编译器错误,但#2会出错。另请注意,编译器(至少gcc)不会编译#1后跟#2,但会编译其中任何一个而不会编译其中任何一个,或者如果#2后跟#1 }。

答案 2 :(得分:0)

我想你想要{}代替;在#1。