Luk*_*uke 3 c++ templates specialization
请考虑以下文件:
foo.h中
template <typename T>
struct Foo
{
int foo();
};
template <typename T>
int Foo<T>::foo()
{
return 6;
}
Run Code Online (Sandbox Code Playgroud)
foo.c的
#include "Foo.H"
template <>
int Foo<int>::foo()
{
return 7;
}
Run Code Online (Sandbox Code Playgroud)
MAIN.C
#include <iostream>
#include "Foo.H"
using namespace std;
int main()
{
Foo<int> f;
cout << f.foo() << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我编译并运行时,打印7.这里发生了什么?什么时候模板实例化?如果编译器这样做,编译器如何知道不实例化它自己的Foo版本?
Jos*_*vin 17
问题是您违反了一个定义规则.在main.C中,你已经包含了Foo.H但不包括Foo.C(这是有意义的,因为它是一个源文件).编译main.C时,编译器不知道你在Foo.C中专门设置了模板,因此它使用泛型版本(返回6)并编译Foo类.然后,当它编译foo.c的,它看到一个完整的专业化,它可以编译马上 -它不需要等待它在某处被实例化,因为所有的类型都填充(如果你有两个模板参数,只专门的,这不是这种情况),它编译一个新的和不同的 Foo类.
通常,同一事物的多个定义会导致链接器错误.但模板实例化是"弱符号",这意味着允许多个定义.链接器假设所有定义都是相同的,然后随机选择一个(好吧,可能始终是第一个或最后一个,但只是作为实现的巧合).
为什么要让它们变弱?因为Foo可能在多个源文件中使用,每个源文件都是单独编译的,并且每次在编译单元中使用Foo时都会生成新的实例化.通常情况下,这些都是多余的,因此将它们扔掉是有道理的.但是你违反了这个假设,通过在一个编译单元(foo.C)中提供专门化而不是另一个(main.C).
如果在Foo.H中声明模板特化,那么当编译main.C时,它不会生成Foo的实例化,因此确保程序中只存在一个定义.