分享
为什么问答平台  ›  专栏  ›  技术社区  ›  ZloiAdun

显式模板实例化如何影响链接器可以找到的内容? - How do explicit template instantiations affect what the linker can find?

  •  10
  • ZloiAdun  · 技术社区  · 2 月前

    请看下面的代码并澄清我的疑问。

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

    2. 如果我将test.cpp代码放在test.h和remve 2中,那么它可以正常工作。为什么?

    .

    // 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 回复  |  直到 9 年前
        1
  •  13
  •   David Rodríguez - dribeas    9 年前

    在这两种情况下,您都在执行显式实例化。在第二种情况下,只有 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 编译器看不到 foo 也不 bar 定义,因此它不能实例化方法。在处理main.cpp时,编译器很乐意接受main中的代码,因为您告诉它 ABC 是一个模板,它有这两个函数,并假定它们将在其他翻译单元中定义。

    在包含test.cpp的翻译单元中,编译器可以看到两个方法定义,并且可以完全处理这两个实例化(方法/类)。如果只存在方法实例化([1]),编译器将只生成该方法,并将离开 酒吧 未定义。所以任何包含test.h的代码,都是针对编译后的test.cpp的链接,并且只使用 方法将编译和链接,但使用 酒吧 由于未定义,将无法链接。

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

        2
  •  0
  •   DS.    9 年前

    (这是我原始答案的编辑版本,由大卫·罗德里格斯的观察所提示。)

    #1 实例化类模板,并作为模板的一部分实例化其所有方法。

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

    如果在bar()中引入类型相关的错误(例如 void *x = b; )您将得到一个编译器错误 α1 但不能 α2 . 还要注意,编译器(至少是gcc)不会编译 α1 然后 α2 ,但将编译其中一个而不编译另一个,或者如果 α2 后面跟着 α1 .

        3
  •  0
  •   Gabriel Ščerbák    9 年前

    我猜你想要而不是;在1。