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

C++ 为什么显式模板实例化的位置很重要,c++,templates,explicit,C++,Templates,Explicit,假设我在a.h #include <iostream> template<bool b> class A { public: void print(std::ostream& out); }; main.cpp中的主程序示例可以是 #include "a.h" int main() { A<true> a; a.print(std::cout); } 为什么会这样 编辑:生成要编译的文件 main : main.o a.o

假设我在
a.h

#include <iostream>

template<bool b>
class A { 
public:
  void print(std::ostream& out);
};
main.cpp
中的主程序示例可以是

#include "a.h"

int main() {
  A<true> a;
  a.print(std::cout);
}
为什么会这样

编辑:生成要编译的文件

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
A类模板;
甲级模板;
同样的原因通常期望模板代码在标头本身中定义的原因。要执行显式实例化,您(编译器)需要能够查看模板类的整个定义,这在
main.cpp
中是不可能的


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

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

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

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

我想原因包括:

  • 翻译单元中的一些成员函数可能有几个不同的明确专门化;为了程序员的利益,有一个明确的规则来说明哪一个将被实例化是有意义的

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


也适用于VS2012。我这样做了,并且我将订单更改为Dejanmentioned@jogojapan -- +1. 我已经删除了我的评论,上面说它是用clang32和gcc48编译的。如果将三个文件的内容剪切并粘贴到一个文件中(就像我最初在测试中所做的那样),任何编译器和任何顺序都可以编译。在Dejan发布Makefile后,我能够用任何版本的clang和gcc重现错误。@LeonidVolnitsky好的,酷!所以我猜只有VS没有以正确的方式实现这一点?我不确定我是否理解你的答案。我的困惑在于
a.cpp
@DejanJovanović中语句的重新排序:啊,我的误解,那么它看起来像是一个编译器的东西,它在VS2010上工作
#include "a.h"

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

template<bool b>
void A<b>::print(std::ostream& out) {
  out << "A" << b;
}
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
template class A<true>;
template class A<false>;