1

(不再那么新的)C++11 标准引入了extern模板关键字。它的目的是告诉编译器不应在使用时实例化模板,而是将在另一个翻译单元中实例化它(因此在链接时会有一个可用的实例化) - 至少 AFAIK。

现在,即使在 C++11 之前的时代,我们也使用类似的东西将模板类的声明/定义与其实例化分开,以加快编译速度,例如:

point.h:类定义

template <int dim> struct Point {
  ...
  void foo();
  ...
};

point.cpp : 方法定义

#include "point.h"
template <int dim>
void Point<dim>::foo() {
  ...
}

point_2d.cpp : 类实例化(2D 版本)

#include "point.cpp"
template struct Point<2>;

point_3d.cpp : 类实例化(3D 版本)

#include "point.cpp"
template struct Point<3>;

main.cpp : 2D 和 3D 点的使用

#include "point.h"
int main(int, char**) {
    Point<2> p;
    p.foo();
}

现在我想知道:

  • 我们的方法是有效的 C++(03 或 11)代码还是我们只是幸运地工作了?
  • 使用 C++11,我们是否能够通过包含point.cppinmain.cpp和声明来实现相同的目标extern template <int dim> struct Point;
4

3 回答 3

1

C++11extern用于告诉编译器不要实例化模板,并且语法使用具体类型,与问题中建议的语法不同:

extern template struct Point<2>; 

使用 C++03 时,编译器必须实例化模板,只要它Point<2>在翻译单元中观察到,而使用 C++11 时,它知道它必须与 extern 关键字结合使用。

对于您的问题,您在 C++03 中所做的是将模板的定义分离到一个单独的头文件中(带有cpp后缀,见下文),并且该方法仍然适用于 C++11:

#include "point.ipp"

extern template struct Point<2>; // instantiated elsewhere

int main(int, char**) {
    Point<2> p;
    p.foo();
}

主观上,我也非常不喜欢cpp模板头文件的后缀,所以我想提请您注意。这是令人困惑和误导的,尤其是当人们看到另一个 cpp 文件中包含一个 cpp 文件时。

考虑使用ipporixx作为文件扩展名,分别与hppand结合使用hxx,更清楚的是,该文件包含特定模板的定义/实现。

于 2014-03-22T09:54:59.343 回答
1

我们的方法是有效的 C++(03 或 11)代码还是我们只是幸运地工作了?

您的用法是有效的,但不是规范的。更常见的 C++98 样式会将显式实例化定义与实现组合在point.cpp文件中。

// point.h

template <int dim> struct Point {
  ...
  void foo();
  ...
};

 

// point.cpp

#include "point.h"

template <int dim>
void Point<dim>::foo() {
  ...
}

// Now the implementation is available, so this is the time to use it:
template struct Point<2>;
template struct Point<3>;

使用 C++11,我们是否能够通过包含point.cppinmain.cpp和声明来实现相同的目标extern template <int dim> struct Point;

你永远不应该#include文件.cpp。规范样式是将函数模板实现放在头文件中,直接放在point.h名为 eg 的模板实现文件中或放在头文件中point.hpp

C++11 带来的好处是你可以有更快的编译时间,也可以Point<4>通过隐式特化来使用。但是,将实现放在具有extern专业化的标头中不会加快编译速度Point<2>,并且Point<3>.

你不能从字面上说extern template <int dim> struct Point;。标题需要列出所有专业:

extern template struct Point<2>;
extern template struct Point<3>;

将所有专业委托给其他地方是export模板的预期目的。这是一个 C++98 特性,被证明太难实现,因此从 C++11 标准中删除。

于 2015-01-07T00:39:48.730 回答
0

您的方法是有效的 C++ 代码,应该在 C++03 和 C++11 中都有效。它被称为显式实例化:

template struct Point<2>;

在应用于类模板时,它显式地为当前翻译单元中的某个模板参数列表实例化类模板的所有成员。使用这种方法,可以很容易地创建模板库,其中可能的模板参数集是预先知道的(在您的情况下,Point可以是 2D 和 3D,但不能是 1D、4D 等)。

在 C++11 中,当您添加显式实例化指令关键字时extern

extern template struct Point<2>;

它成为一个声明,而不是一个定义。这种事情的行为类似于extern变量的常用关键字。显式模板实例化声明可以通过以下方式与显式实例化一起使用:

// point.h

template <int dim> struct Point {
  ...
  void foo();
  ...
};

extern template struct Point<2>;
extern template struct Point<3>;

#include "point.hpp"


// point.hpp

#include "point.h"

template <int dim>
void Point<dim>::foo() {
  ...
}

// point.cpp

#include "point.hpp"

template struct Point<2>;
template struct Point<3>;

使用这样的代码,您可以获得与您的代码相同的结果,但此外,您还允许您的代码的用户使用Point<1>Point<4>以及Point类模板的其他专业化(如果他们愿意)。如果没有extern template struct Point<2>;andextern template struct Point<3>;指令,即使对于模板参数,Point类模板也会在用户代码中隐式实例化,这会降低显式实例化(和)的含义。23template struct Point<2>;template struct Point<2>;

于 2014-03-22T14:30:24.827 回答