我有一个具有特化的显式实例化模板类:
// a.hh
#pragma once
template<int N>
struct A {
int foo();
};
// a.in
#include "a.hh"
template<>
int A<1>::foo() { return 1; } // specialization for N=1
template<>
int A<2>::foo() { return 2; } // specialization for N=2
// a1.cc
#include "a.in"
template struct A<1>; // explicit instantiation for N=1
// a2.cc
#include "a.in"
template struct A<2>; // explicit instantiation for N=2
以上文件用g++ 4.9.2编译成静态库:
g++ -Wall -c -o a1.o a1.cc
g++ -Wall -c -o a2.o a2.cc
ar rcs libtest.a a1.o a2.o
我希望 a1.o 包含 A<1>::foo(),而 a2.o 包含 A<2>::foo(),但不是相反,因为每个实例中只有一个实例.cc 文件。
然而,事实证明,两个目标文件都包含这两个函数。VS2015RC 还给出了链接器警告:
a1.obj : warning LNK4006: "public: int __thiscall A<1>::foo(void)" already defined in a2.obj; second definition ignored
a1.obj : warning LNK4006: "public: int __thiscall A<2>::foo(void)" already defined in a2.obj; second definition ignored
为什么?
此外,如果我注释掉 N=2 的特化,使用 g++ 它仍然会静默编译,即使显式实例化的 N=2 案例具有未解析的功能......(VS2015RC 警告说“没有为显式模板实例化请求提供合适的定义”,正如预期的那样)。
澄清- 根据标准(14.7.3.6):
如果类模板的 [..] 成员是显式特化的,则应在第一次使用该特化之前声明该特化,这将导致发生隐式实例化,在发生这种使用的每个翻译单元中[.]
这段话(隐含地)指出,需要使用专门化才能对其进行实例化。
我的问题是 A<2>::foo() 在 a1.o 中被隐式实例化,即使在那个翻译单元中没有使用这个规范。