替代每个源文件中的"extern模板"

Tru*_*lis 5 c++ templates c++11

我正在开发一个库,其中我们的许多核心对象都是模板,其中一个特定的实例显示在项目中的大多数文件中,以指向该模板实例化的智能指针的形式出现.我在单个源文件中显式实例化这些模板.我们最近切换到C++ 11,我正在尝试使用新的

extern template class MyTemplate<double>;
Run Code Online (Sandbox Code Playgroud)

加快编译速度.我的第一个问题是我是否使用了智能指针

MyTemplate<double>
Run Code Online (Sandbox Code Playgroud)

隐式实例化模板并需要文件顶部的"extern模板.."以避免重复实例化.

我的第二个问题是,是否有一些替代方案可以添加所有这些

extern template class MyTemplate<double>;
Run Code Online (Sandbox Code Playgroud)

到每个源文件.对于我定义的每个模板,只需稍微繁琐地点击智能指针的每个实例,并确保我在该文件中有正确的"外部模板"行.我还可以看到为代码的未来开发人员执行此约定有点困难,因为他们可能会添加模板实例化并忘记相应的extern模板行,尤其是因为不会生成错误.

Rei*_*ica 5

如果您确定要显式实例化模板,只需将显式实例化声明(该extern template行)放入标头中,即可将其包含在模板中。

实例化文件中存在这一行是没有问题的,只要显式实例化定义(非extern一个)显式实例化声明(extern一个)之后,标准便会明确允许它。裁定在C ++ 14 14.7.2 / 11中;C ++ 11中也存在相同的规则。


5go*_*der 5

您可以将extern template声明直接放在template定义的头文件中。例如:

在文件中useful.hxx

#ifndef USEFUL_HXX
#define USEFUL_HXX

namespace my
{

  template <typename T>
  T
  do_useful_stuff(T x)
  {
    return x;
  }

  extern template int   do_useful_stuff(int);
  extern template float do_useful_stuff(float);
  // Potentially many more...

}  // namespace my

#endif  // ifndef USEFUL_HXX
Run Code Online (Sandbox Code Playgroud)

在文件中useful.cxx

#include "useful.hxx"

namespace my
{

  template int   do_useful_stuff(int);
  template float do_useful_stuff(float);
  // Potentially many more...

}  // namspace my
Run Code Online (Sandbox Code Playgroud)

最后在文件中main.cxx

#include <iostream>
#include "useful.hxx"

int
main()
{
  std::cout << my::do_useful_stuff(42) << std::endl;
  std::cout << my::do_useful_stuff(1.0f) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

您现在可以进行编译useful.cxxmain.cxx然后将两者链接在一起。

到目前为止,一切都很好。但是,如您所见,这仍然是重复的。如果您不担心某些预处理器魔术,则可以将常见内容分解为文件useful.txx

#ifndef MY_EXTERN
#error "Please '#define MY_EXTERN' to 'extern' or '' before '#include'ing this file."
#endif

namespace my
{

  MY_EXTERN template int   do_useful_stuff(int);
  MY_EXTERN template float do_useful_stuff(float);
  // Potentially many more...

}  // namspace my
Run Code Online (Sandbox Code Playgroud)

然后#includeuseful.cxx

#include "useful.hxx"

#define MY_EXTERN /* empty*/
#include "useful.txx"
#undef MY_EXTERN
Run Code Online (Sandbox Code Playgroud)

useful.hxx

#ifndef USEFUL_HXX
#define USEFUL_HXX

#ifndef MY_USE_EXTERN_TEMPLATES
#define MY_USE_EXTERN_TEMPLATES 0
#endif

namespace my
{

  template <typename T>
  T
  do_useful_stuff(T x)
  {
    return x;
  }

}  // namespace my

#if MY_USE_EXTERN_TEMPLATES
#define MY_EXTERN extern
#include "useful.txx"
#undef MY_EXTERN
#endif

#endif  // ifndef USEFUL_HXX
Run Code Online (Sandbox Code Playgroud)

如所示。请注意,我还利用了使extern条件声明成为条件的机会,以便客户端可以将您的头文件与任一实例化模型一起使用。因此,我们也更新了main.cxx

#define MY_USE_EXTERN_TEMPLATES 1

#include <iostream>
#include "useful.hxx"

int
main()
{
  std::cout << my::do_useful_stuff(42) << std::endl;
  std::cout << my::do_useful_stuff(1.0f) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

再次,我们可以编译useful.cxxmain.cxx和生成的对象文件链接在一起。如果我们不将其设置#define MY_USE_EXTERN_TEMPLATES为1 in main.cxx,则可以一次编译该文件并将其链接。