我从gcc 4.8.3和clang 3.2获得了一致的行为,但不明白为什么会这样。尽管我有一个类模板的显式实例化,但是当我使用模板的完全专用的实例时,代码没有被生成并且我得到一个未定义的符号。
我在文件中有一个简单的类模板定义' temp.hpp'
#pragma once
template <typename T1>
class C
{
public:
C (T1 c) : d_c(c) {};
~C () = default;
void print ();
private:
T1 d_c;
};
注意方法&#39; print()&#39;已声明,但未在此处定义。我想要.cpp文件中的定义,它将专门用于不同的类型。
所以在temp.cpp文件中我有print()方法的默认定义
#include "temp.hpp"
#include <iostream>
template<typename T1>
void
C<T1>::print ()
{
std::cout << "Printing: " << d_c << std::endl;
}
后面是类型&#39; float&#39;:
的类的特化template <>
class C <float>
{
public:
C (float f) : d_f(f) {};
~C () = default;
void print ()
{
std::cout << "float: " << d_f << std::endl;
}
private:
float d_f;
};
由于定义在.cpp文件中,我必须显式实例化我将使用的所有特化。所以我有:
template class C<int>;
template class C<float>;
我的测试的驱动程序在test.cpp中看起来像这样:
#include "temp.hpp"
int main()
{
int i = 1;
C<int> c_int(i);
float f = 1.2;
C<float> c_float(f);
c_int.print();
c_float.print();
}
编译和链接后,我得到错误:
test.cpp: undefined reference to `C<float>::print()'
C
nm -C temp.o
...
0000000000000000 W C<int>::print()
0000000000000000 W C<int>::C(int)
0000000000000000 W C<int>::C(int)
...
正如我之前提到的,这与gcc和clang一致,所以我假设有一些我不明白的语言规则。
请注意,如果我在文件temp.cpp中添加了print()方法的用法,那么代码就会生成,但这很愚蠢,而且在我的实际代码中是不可能的。对于这个简单的测试用例,它看起来像:
void foo ()
{
C<float> s(1.3);
s.print();
}
在推动这个小测试的真实代码中,我的模板有3个模板参数,这些参数组合起来扩展到约30个代码的排列。有一两个我需要专门化的东西,它做了不同的事情,但另外两个我可以独自留下。
关于我出错的地方的任何指针或者为什么显式实例化不应该生成代码的语言参考都非常感激。我花了1/2的时间阅读显式实例化中的所有其他stackoverflow帖子,并相信我正确使用它。
答案 0 :(得分:6)
来自[temp.expl.spec]:
如果模板,成员模板或类模板的成员明确专门化,那么该专业化 应在第一次使用该特化之前声明,这将导致隐式实例化 发生,在每个翻译单元中发生此类用途;无需诊断。如果是程序 不提供显式特化的定义,并且在某种程度上使用特化 这将导致隐式实例化发生或成员是虚拟成员函数, 程序格式错误,无需诊断。
我们在temp.cpp中明确地专门化了C
,但是在test.cpp中,它在使用之前没有被声明。因此,您的代码格式错误,无需诊断。您只需将C<float>
的声明移至temp.hpp
始终注意明确的专业化。该标准认真对待非常:
为函数模板,类模板[...]放置显式特化声明可能会影响程序是否格式正确 显式专业化声明及其实例化点的相对定位 在上面和下面指定的翻译单元中。 写专业时,要小心它 地点;或者使它编译将是一个试图点燃其自焚的试验。