C++ 11:显式实例化声明与显式实例化定义

Mar*_*son 20 c++ templates c++11

C++ 03的显式模板的实例化定义和C++ 11的显式模板的实例化声明之间有什么区别?

我的意思是为什么实例化定义不足以阻止编译器为其他类型生成实现?下面的例子有什么问题:想象一下我将模板声明和定义分成两个单独的文件:

#pragma once

template<typename T>
class A
{
public:
    A(T t);

private:
    T _t;
};
Run Code Online (Sandbox Code Playgroud)

A.cpp

#include "A.h"

template<typename T>
A<T>::A(T t) : _t(t) {}

template class A<int>; // explicit instantiation
Run Code Online (Sandbox Code Playgroud)

main.cpp中

#include "A.h"

int main()
{
    A<int> a(5); // fine, compiler generates header file,
                 // linker links with implementation from A.cpp file

    // A<float> b(3.14f); // linker error, as expected
}
Run Code Online (Sandbox Code Playgroud)

上面的示例中是否有任何编译时间开销?如果我理解正确,在这种情况下,在单独的*.cpp文件中使用显式实例化定义(以及模板的实现),我使编译器无法使用任何其他类型隐式实例化模板.因此,为什么显式实例化声明有单独的语法?

如果我已经使用显式实例化定义隐藏了A.cpp文件中的实现,并且阻止编译器为其他类型生成主体,那么显式实例化声明如何加快编译时间."显式实例化声明"是否与"显式实例化定义"有某种关联,我的意思是我应该同时使用它们,还是这些是完全独立的特性(例如,只有在未使用显式实例化定义时才能使用显式实例化声明)?

我是否正确,明确的实例化定义只是在没有其他翻译单元使用给定类型实例化模板的情况下触发错误?

Jon*_*ely 28

当你在文件中放置一个显式的实例化定义时A.cpp,编译器在编译时应该如何知道它main.cpp?答案是它不能,所以它仍然会实例化所使用的模板main.cpp,在你的情况下使用显式实例化定义是没用的,并没有帮助.

显式实例化的声明告诉编译器"不要打扰实例化这个模板,我将自己,在程序中的其他地方",并且定义是履行该承诺的.

显式实例化必须只在一个文件中定义一次,但可以在不同的文件中多次声明.这对于模板来说并不是唯一的,在C和C++中,相同的规则适用于(非内联)函数:您可以在不同的文件中多次声明它们(通常通过将声明放在标题中)然后您必须准确定义函数一次,在一个文件中.

因此,为了使您的示例正常工作,您应该在A.h以下位置添加声明:

extern template class A<int>; // explicit instantiation declaration
Run Code Online (Sandbox Code Playgroud)

  • @MarcAndreson,它可以工作,但编译器将在每个文件中再次实例化模板,链接器将丢弃重复项.那浪费时间.在`A.cpp`中使用显式实例化意味着编译器只需要生成一次类,但是为了利用编译器**在编译`B.cpp`和`main时必须知道显式实例化存在**.cpp`,这就是你宣布它的原因.但是如果你不理解这个好处那么就不要使用显式实例化,没有人强迫你使用它们. (4认同)
  • 编译器在`B.cpp`中实例化类'A <int>`并发出对函数`A <int> :: A(int)`的未定义引用.然后链接器在链接时查找定义.如果在`Ah`中使用显式实例化定义,那么编译`B.cpp时编译器将不会实例化`A <int>` (3认同)
  • 让我们[在聊天中继续讨论](http://chat.stackoverflow.com/rooms/58431/discussion-between-jonathan-wakely-and-marcandreson)。 (2认同)