假设我在A
a.h
#include <iostream>
template<bool b>
class A {
public:
void print(std::ostream& out);
};
并在a.cpp
中定义打印方法(明确设置true
和false
)
#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;
}
答案 0 :(得分:8)
我认为没有一个好的自然解释为什么会这样。显然,编译器可以看到成员函数的定义,即使它是在显式实例化之后提供的 - 因为它位于同一个文件中。
但是,编译器不需要这样做;事实上,标准明确禁止这样做:
(§14.7.2/ 9)命名类模板特化的显式实例化定义显式实例化类模板特化,并且是仅在实例化时定义的那些成员的显式实例化定义。
我想其原因包括以下内容:
稍后在翻译单元中,某些成员函数可能有几种不同的显式特化;同样符合程序员的兴趣,有一个明确的规则来确定哪些将被实例化;
当模板隐式实例化时,只考虑在实例化之前定义的特化;因此隐式和显式实例化的规则是相同的。
答案 1 :(得分:1)
template class A<true>;
template class A<false>;
同样的原因为什么通常期望模板代码在标头本身中定义。要执行显式实例化,您(编译器)需要能够查看模板类的整个定义,这是main.cpp
无法实现的。
但是a.cpp
可以访问类的所有定义(这里是print方法),因此显式实例化在那里工作。