即使使用显式实例化,也不会为显式专用模板生成代码

Jay*_*Jay 5 c++ templates instantiation specialization c++11

我从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;
};
Run Code Online (Sandbox Code Playgroud)

请注意,方法'print()'已声明,但未在此处定义.我想要.cpp文件中的定义,它将专门用于不同类型.

所以在temp.cpp文件中我有print()方法的默认定义

#include "temp.hpp"
#include <iostream>

template<typename T1>
void
C<T1>::print ()
{
  std::cout << "Printing: " << d_c << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

然后是类型'float'的类的特化:

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;
};
Run Code Online (Sandbox Code Playgroud)

由于定义在.cpp文件中,我必须显式实例化我将使用的所有特化.所以我有:

template class C<int>;
template class C<float>;
Run Code Online (Sandbox Code Playgroud)

我的测试的驱动程序在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();
}
Run Code Online (Sandbox Code Playgroud)

编译和链接后,我得到错误:

test.cpp: undefined reference to `C<float>::print()'
Run Code Online (Sandbox Code Playgroud)

正确生成C <int>的目标代码.我可以用nm看到它:

nm -C temp.o
...
0000000000000000 W C<int>::print()
0000000000000000 W C<int>::C(int)
0000000000000000 W C<int>::C(int)
...
Run Code Online (Sandbox Code Playgroud)

正如我之前提到的,这与gcc和clang一致,所以我假设有一些我不明白的语言规则.

请注意,如果我在文件temp.cpp中添加了print()方法的用法,那么代码就会生成,但这很愚蠢,而且在我的实际代码中是不可能的.对于这个简单的测试用例,它看起来像:

void foo () 
{
  C<float> s(1.3);
  s.print();
}
Run Code Online (Sandbox Code Playgroud)

在推动这个小测试的真实代码中,我的模板有3个模板参数,这些参数组合起来扩展到代码的大约30个排列.有一两个我需要专门化的东西,它做了不同的事情,但另外两个我可以独自留下.

关于我出错的地方的任何指针或者为什么显式实例化不应该生成代码的语言参考都非常感激.我花了半天时间阅读显式实例化的所有其他stackoverflow帖子,并相信我正确使用它.

Bar*_*rry 6

来自[temp.expl.spec]:

如果模板,成员模板或类模板的成员是显式专用的,则应在首次使用该特之前声明该特化,这将导致发生隐式实例化,发生此类使用的每个翻译单元中; 无需诊断.如果程序没有提供显式特化的定义,并且特殊化的使用方式会导致隐式实例化或成员是虚拟成员函数,则程序格式错误,无需诊断.

我们明确地专注C于temp.cpp,但是在test.cpp中,它在使用之前没有声明.因此,您的代码格式错误,无需诊断.您只需将声明移动C<float>到temp.hpp即可

始终要小心明确的专业化.该标准非常重视它们:

函数模板,类模板的显式特化声明的放置,可以根据显式特化声明的相对位置及其在翻译单元中的实例化点的相对位置来影响程序是否格式正确,如上所述以下.写专业时,要注意它的位置; 或者使它编纂将是一种试图点燃其自焚的试验.

  • 你没有引用以下段落.我很失望 :) (2认同)