2

我有一个具有特化的显式实例化模板类:

// 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 中被隐式实例化,即使在那个翻译单元中没有使用这个规范。

4

2 回答 2

2

你的专长不是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
于 2015-07-10T14:50:54.590 回答
1

我会说你的代码

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

这是成员函数的明确定义,因此不能重复执行。因此,请确保仅在一个翻译单元内。

14.7.3 显式专业化

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

于 2015-07-10T14:58:51.667 回答