特化模板的多个实例化

Multiple instantiation of specialized templates

本文关键字:实例化      更新时间:2023-10-16

我有一个带有专门化的显式实例化的模板类:

// 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。0包含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[…]类模板的]成员是显式特化的,那么该特化应该在第一次使用该特化之前声明,该特化会导致隐式实例化发生,在每个使用该特化的翻译单元中[.]

这段话(隐式地)指出,需要使用专门化才能实例化它。

我的问题是A<2>::foo()在a1中隐式实例化。

您的专门化不是inline。所以你有一个翻译单位的定义包括a.in

添加inline关键字:

template<>
inline int A<1>::foo() { return 1; } // specialization for N=1

或移动CPP文件中的定义:

// a1.cc
#include "a.hh"
template<>
int A<1>::foo() { return 1; } // specialization for N=1
template struct A<1>; // explicit instantiation for N=1

我想说你的代码

template<>
int A<1>::foo() { return 1; } // specialization for N=1

是成员函数的显式定义,因此不能执行两次。因此,确保只在一个翻译单元内。

14.7.3显式特化

5显式特化类的成员不是隐式的从类模板的成员声明中实例化;相反,类模板特化的成员应该自己如果需要定义,则显式定义。