6

假设我声明了一个模板Aa.h

#include <iostream>

template<bool b>
class A { 
public:
  void print(std::ostream& out);
};

并在中定义 print 方法(使用anda.cpp的显式实例化)truefalse

#include "a.h"

template<bool b>
void A<b>::print(std::ostream& out) {
  out << "A" << b;
}

template class A<true>;
template class A<false>;

一个示例主程序main.cpp可以是

#include "a.h"

int main() {
  A<true> a;
  a.print(std::cout);
}

上面的小项目编译得很好。

问题:如果我将显式实例化置于print方法定义之上(in 中a.cpp),代码将不再编译,并出现通常的undefined reference to A<true>::print(...)错误。

#include "a.h"

template class A<true>;
template class A<false>;

template<bool b>
void A<b>::print(std::ostream& out) {
  out << "A" << b;
}

为什么会这样?

编辑:要编译的 Makefile

main : main.o a.o
    g++ main.o a.o -o main

main.o : main.cpp
    g++ -c main.cpp

a.o : a.cpp 
    g++ -c a.cpp
4

2 回答 2

9

我不认为有一个很好的自然解释为什么会这样。显然,编译器可以看到成员函数的定义,即使它是在显式实例化之后提供的——因为它位于同一个文件中。

但是,编译器不需要这样做;事实上,标准明确禁止它:

(第 14.7.2/9 节)命名类模板特化的显式实例化定义显式实例化类模板特化,并且是仅在实例化点已定义的那些成员的显式实例化定义。

我想这其中的原因包括以下几点:

  • 翻译单元后面的一些成员函数可能有几个不同的显式特化;为了程序员的利益,有一个明确的规则来说明哪些将被实例化是有道理的;

  • 当模板被隐式实例化时,只考虑在实例化点之前定义的特化;因此对于隐式和显式实例化规则是相同的。

于 2013-01-04T06:16:55.773 回答
1
template class A<true>;
template class A<false>;

与通常期望在标头本身中定义模板代码的原因相同。要执行显式实例化,您(编译器)需要能够查看模板类的完整定义main.cpp,而您的.

但是a.cpp可以访问类的所有定义(这里是 print 方法),所以显式实例化在那里工作。

于 2013-01-04T06:06:39.750 回答