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

时间:2014-07-31 10:39:09

标签: c++ templates c++11

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

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

A.H

#pragma once

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

private:
    T _t;
};

A.cpp

#include "A.h"

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

template class A<int>; // explicit instantiation

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

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

如果我已经使用显式实例化定义在A.cpp文件中隐藏了实现,并且阻止编译器生成正文,那么显式实例化声明如何加快编译时间对于其他类型。 “显式实例化声明”是否以某种方式与“显式实例化定义”相关,我的意思是我应该同时使用它们,还是这些是完全独立的特性(例如,只有在未使用显式实例化定义的情况下才能使用显式实例化声明)? / p>

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

2 个答案:

答案 0 :(得分:26)

当您在文件A.cpp中放置显式实例化定义时,编译器在编译main.cpp时应该如何知道它?答案是它不能,所以它仍然会实例化main.cpp中使用的模板,在你的情况下使用显式实例化定义是没用的,也无济于事。

显式实例化的声明对编译器说“不要打扰实例化这个模板,我将自己这样做,在程序的其他地方”,并且定义是实现这个承诺的。

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

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

extern template class A<int>; // explicit instantiation declaration

答案 1 :(得分:0)

  

显式实例化声明(一个extern模板)跳过了隐式实例化步骤:否则会导致隐式实例化的代码将改用其他地方提供的显式实例化定义(如果不存在此类实例,则会导致链接错误)。通过在使用该模板的源文件之一之外的所有文件中显式声明一个模板实例化,并在其余文件中显式定义它,可以减少编译时间。   Source

此处main.cppA.h中的声明将阻止main.cpp根据模板的哪些部分可见(即{{1})生成(在编译时)代码。基于}的A.h专业化:

A<int>

但是class A<int> { public: A(int t); private: int _t; }; 代码确实需要知道main.cpp存在,这意味着它必须执行某种实例化才能学习所有A<int>::A(int)成员,而这正是{{基于1}}的{​​{1}}实例化。

因此,尽管受制于每个编译器/平台配置文件,但它在这里的用处并不十分明显。