c++ - 即使有显式实例化,也没有为显式专用模板生成代码

标签 c++ templates c++11 instantiation specialization

我从 gcc 4.8.3 和 clang 3.2 得到了一致的行为,但不明白为什么会这样。尽管我有一个类模板的显式实例化,但当我使用模板的完全专用实例时,代码没有生成并且我得到一个 undefined symbol 。

我在文件“temp.hpp”中有一个简单的类模板定义

#pragma once

template <typename T1>
class C 
{
public:
  C (T1 c) : d_c(c) {};
  ~C () = default;

  void print ();
private:
  T1 d_c;
};

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

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

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

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

接着是“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;
};

并且由于定义在 .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 看到它:

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 个代码排列。其中一两个我需要一个特化来做一些不同的事情,但其他 28 个我可以不管。

非常感谢任何关于我出错的地方的指示或为什么显式实例化不应该生成代码的语言引用。我每天花 1/2 的时间阅读所有其他关于显式实例化的 stackoverflow 帖子,并相信我正在正确使用它。

最佳答案

来自 [temp.expl.spec]:

If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required.

我们明确地专注于 C在 temp.cpp 中,但在 test.cpp 中,它在使用前未声明。因此,您的代码格式错误,不需要诊断。您只需移动 C<float> 的声明即可。进入 temp.hpp

始终注意显式特化。该标准非常重视它们:

The placement of explicit specialization declarations for function templates, class templates, [...], can affect whether a program is well-formed according to the relative positioning of the explicit specialization declarations and their points of instantiation in the translation unit as specified above and below. When writing a specialization, be careful about its location; or to make it compile will be such a trial as to kindle its self-immolation.

关于c++ - 即使有显式实例化,也没有为显式专用模板生成代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31751138/

相关文章:

c++ - 如何解决数独问题,以便通过交换任何两个相邻的子网格我仍然得到有效答案?

c++ - 模板空括号初始化推导

c++ - 画一条线或许多点之间的区别

c++ - 如何使用 variadic size_t 模板将多个 std::tuple_element 分配为函数参数

c++ - 绘制一个对象,比较模板缓冲区的两个不同值

c++ - 相关函数族的通用函数(例如 std::stoi、std::stof、std::stod 等)

模板类的实例化对象上的 C++ 模板元函数

templates - C++/CLI 中的函数模板

c++ - 抽象类和虚拟构造函数的替代方法

c++ - 如何在 cpp 中使用 CRLF 分隔符拆分字符串?