查看 tps.hpp 中的base::m_visible
方法(这是“默认”):
#include <sstream>
#include <iostream>
template <typename T> struct base
{
void m_log() const;
void m_visible() const;
};
struct inheritor: base<inheritor>
{
void log() const;
};
template <typename T> void base<T>::m_log() const
{
std::ostringstream os;
m_visible();
os.str(""); // We have «default/default» if comment here, :-0
std::cout << os.str();
}
template <typename T> void base<T>::m_visible() const
{
std::cout
<< "default" << std::endl
;
}
专门用于 tps_spec.cpp 中的inheritor
结构(名为«spec»):
#include "tps.hpp"
template <> void base<inheritor>::m_visible() const
{
std::cout
<< "spec" << std::endl
;
}
void inheritor::log() const
{
m_log();
}
并从 tps_main.cpp 进一步调用:
#include "tps.hpp"
int main(int, char **argv)
{
std::cout << argv[0] << ": ";
inheritor().m_log(); // We have «spec/spec» if call inheritor::log
return 0;
}
结果取决于编译单元的顺序(GCC 4.8.4):
g++ -Wall -O3 -o tps1 tps_spec.cpp tps_main.cpp && g++ -Wall -O3 -o tps2 tps_main.cpp tps_spec.cpp && ./tps1 ; ./tps2
./tps1: spec
./tps2: default
只有优化-O3
才会发生这种情况。任何以评论为标记的实验版都会产生不同的结果。的为什么吗
答案 0 :(得分:2)
因为这是未定义的行为。
如果模板是专用的,那么这种专业化必须是&#34;可见&#34;无处不在。
您在一个翻译单元中声明并实现专业化。该专门的模板声明基本上完全是内部的翻译单元,专业化只对该翻译单元可见。您的tps_main
翻译单元对模板专业化没有可见性,也不知道任何知识;因此,将此模板特化可见的不同翻译单元将其链接在一起会导致未定义的行为。
您需要声明 并定义 (这里有一些不太相关的例外)头文件中的特化,以便包含标题的每个翻译单元具有模板定义的文件也将具有专业化的定义。
模板专业化不是&#34;实施&#34;某种模板的模板,用于专门的模板实例。模板专门化基本上是一个完全独立的类声明。因此,如果您有一个使用该类的翻译单元,则必须声明该类。
您不能在一个翻译单元中声明一个类,并且希望在不同的翻译单元中使用它而不让其他翻译单元看到该声明。
基本上,您链接在一起的所有翻译单元必须具有相同的类,对象和模板声明。这包括模板专业化。
这只是说C++ templates can only be portably defined in header files。
的方式