C++ C++;11:显式实例化声明与显式实例化定义
C++03的显式模板的实例化定义与C++11的显式模板的实例化声明之间有什么区别 我的意思是为什么实例化定义不足以阻止编译器为其他类型生成实现?下面的示例中有什么错误:假设我将模板声明和定义拆分为两个单独的文件: A.hC++ C++;11:显式实例化声明与显式实例化定义,c++,templates,c++11,C++,Templates,C++11,C++03的显式模板的实例化定义与C++11的显式模板的实例化声明之间有什么区别 我的意思是为什么实例化定义不足以阻止编译器为其他类型生成实现?下面的示例中有什么错误:假设我将模板声明和定义拆分为两个单独的文件: A.h #pragma一次 模板 甲级 { 公众: A(T); 私人: T_T,; }; A.cpp #包括“A.h” 模板 A::A(T):\u T(T){} 模板类别A;//显式实例化 main.cpp #include "A.h" int main() { A<
#pragma一次
模板
甲级
{
公众:
A(T);
私人:
T_T,;
};
A.cpp
#包括“A.h”
模板
A::A(T):\u T(T){}
模板类别A;//显式实例化
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
}
#包括“A.h”
int main()
{
A(5);//好的,编译器生成头文件,
//链接器从.cpp文件链接到实现
//A b(3.14f);//链接器错误,如预期的那样
}
在上面的例子中是否有编译时间开销?如果我理解正确,在这种情况下,在单独的*.cpp文件中使用显式实例化定义(连同模板的实现),我会使编译器无法隐式实例化任何其他类型的模板。因此,为什么显式实例化声明有单独的语法
如果我已经使用显式实例化定义将实现隐藏在.cpp文件中,并且阻止编译器为其他类型生成body,那么显式实例化声明如何加快编译时间。“显式实例化声明”是否与“显式实例化定义”有某种关联,我的意思是我应该同时使用它们,还是它们是完全独立的特性(例如,只有在未使用显式实例化定义的情况下,才能使用显式实例化声明)
我是否认为,显式实例化定义只是在没有其他翻译单元使用给定类型实例化模板时触发错误?当您将显式实例化定义放入文件
A.cpp
中时,编译器在编译main.cpp
时如何知道它在那里?答案是它不能,因此它仍然会实例化main.cpp
中使用的模板,在您的情况下,使用显式实例化定义是无用的,也没有帮助
一个显式实例化的声明对编译器说:“不要麻烦实例化这个模板,我会自己去做,在程序的其他地方”,而定义就是实现这个承诺的东西
显式实例化必须只在一个文件中定义一次,但可以在不同的文件中多次声明。这对于模板没有什么特殊之处,在C和C++中,同样的规则适用于(非内联)函数:您可以在不同的文件中多次声明它们(通常是在声明中放入声明),然后必须在一个文件中定义一次函数。
因此,为了使示例正常工作,您应该在a.h
中添加一个声明:
extern template class A<int>; // explicit instantiation declaration
外部模板类A;//显式实例化声明
显式实例化声明(外部模板)跳过隐式实例化步骤:否则会导致隐式实例化的代码将使用别处提供的显式实例化定义(如果不存在此类实例化,则会导致链接错误)。这可以通过在使用模板实例化的所有源文件(除了一个)中显式声明模板实例化,并在其余文件中显式定义模板实例化来减少编译时间。
在这里,main.cpp
或a.h
中的声明会阻止main.cpp
基于模板的哪些部分是可见的(在编译时)生成代码,即基于a.h
的a
专门化:
class A<int>
{
public:
A(int t);
private:
int _t;
};
A类
{
公众:
A(int t);
私人:
国际;;
};
然而,main.cpp
代码确实需要知道A::A(int)
的存在,这意味着它必须执行某种类型的实例化才能学习所有A
成员,这正是基于A.h
的A
实例化所要做的
所以,是的,这里它的用处并不十分明显——尽管需要根据编译器/平台进行分析。如果我添加另一个翻译单元,比如B.cpp,我只需要像在main.cpp中那样包含“A.h”就可以使用A。这有什么错?我仍然不清楚为什么我需要显式的模板声明,如果这个例子有效的话。@Marcardeson,它有效,但是编译器会在每个文件中再次实例化模板,链接器会扔掉重复的模板。那是浪费时间。在
A.cpp
中使用显式实例化意味着编译器只需要生成一次类,但要利用这一点,编译器必须在编译B.cpp
和main.cpp
时知道显式实例化存在,这就是您声明它的原因。但是如果您不了解其好处,那么就不要使用显式实例化,没有人强迫您使用它们。编译器在B.cpp
中实例化类A
,并发出对函数A::A(int)
的未定义引用。然后链接器在链接时查找定义。如果在A.h
中使用显式实例化定义,那么编译器在编译B.cpp
时不会实例化A
,所以编译器只生成类的声明A,对吗?就好像我已经将类“A_int”的头文件包含到我的翻译单元中一样?但是我想“extern template class A”也会这样做,所以我看不出有什么好处,但我希望我能理解它:(让我们一起来)。
extern template class A<int>; // explicit instantiation declaration
class A<int>
{
public:
A(int t);
private:
int _t;
};