为什么显式模板实例化的位置很重要

时间:2013-01-04 06:01:30

标签: c++ templates explicit

假设我在A

中声明了一个模板类a.h
#include <iostream>

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

并在a.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方法的定义之上(在a.cpp中),则代码不再编译,通常{ {1}}错误。

undefined reference to A<true>::print(...)

为什么会这样?

编辑:Makefile进行编译

#include "a.h"

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

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

2 个答案:

答案 0 :(得分:8)

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

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

  

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

我想其原因包括以下内容:

  • 稍后在翻译单元中,某些成员函数可能有几种不同的显式特化;同样符合程序员的兴趣,有一个明确的规则来确定哪些将被实例化;

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

答案 1 :(得分:1)

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

同样的原因为什么通常期望模板代码在标头本身中定义。要执行显式实例化,您(编译器)需要能够查看模板类的整个定义,这是main.cpp无法实现的。

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