单独编译和模板显式实例化 [英] Separate compilation and template explicit instantiation

查看:292
本文介绍了单独编译和模板显式实例化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

摘要

此问题是要在几个不同的翻译单元中实现单个模板类实例化的单独编译。



问题

对于非模板类,可以将定义放在几个.cpp文件中,并单独编译。例如:



文件啊:

  class A {
public:
void func1();
void func2();
void func3(){/ *在类声明中定义* /}
}

file A1.cpp:

  void A :: func1 * /} 

文件A2.cpp:
$ b

  void A :: func2(){/ * do smth else * /} 

现在我试图做类似于模板类的事情。因为我知道我需要什么实例,我明确实例化模板。我分别编译每个实例化,因为成员函数包含相当大的数学表达式,这可能会在高优化级别显着减慢编译器。所以我尝试了以下操作:

 >  template< typename T> 
class TA {
public:
void func1();
void func2();
void func3(){/ *在类声明中定义* /}
}

文件TA1.cpp:

  
void TA< T> :: func1(){/ * do smth * /}
模板类TA< sometype> ;;

文件TA2.cpp:

  template< typename T> 
void TA< T> :: func2(){/ * do smth else * /}
模板类TA< sometype>

它在Linux上与clang和GCC一起使用,但在重复符号链接期间在Mac上的GCC失败(在这个例子中由于func3,它在TA1.cpp和TA2.cpp中被实例化)。



然后我在标准中忽略了这句话:


C ++ 11.14.7,第5段:

对于给定的模板和一组给定的模板参数, br>
- 显式实例化定义在程序中最多出现一次

- ...


这意味着即使使用显式实例化也不可能(不允许)对模板类进行单独编译(显然不可能使用隐式实例化)?



PS我不在乎,因为我有我的答案,但谁认为它是在这里回答 https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file 错误。

解决方案

再次看看标准,在我看来,唯一合理的选择是使用单个显式模板类实例化结合显式成员函数实例化少量的困难函数。



这(根据14.7.2p9)将实例化类和所有已定义的成员(应包括除非困难成员)。



这样会使我的示例如下所示(假设 TA1.cpp

em>包含简单的函数, TA 中的唯一困难函数是 func2



TA1.cpp:

 模板< typename T& 
void TA< T> :: func1(){/ *simplefunction definition * /}

模板类TA< sometype& / * expl。研究所。类别* /

文件TA2.cpp: b
$ b

  template< typename T> 
void TA< T> :: func2(){/ *difficultfunction definition * /}

template void TA< sometype> :: func2 / * expl。研究所。的成员* /

此方法要求我们为每个困难函数编写显式实例化定义,







什么时候可以使用?不经常。正如这里提到的其他人,不建议将类的定义拆分为多个文件。在我的特定情况下,困难函数包含非平凡类的实例上的复杂数学运算。 C ++模板对于快速编译速度并不出名,但在这种情况下,它是无法忍受的。这些函数调用对方,发送编译器在漫长和内存耗用的扩展/内联重载操作符/模板/等的旅程优化它看到的一切,几乎零改进,但编译持续数小时。在单独的文件中隔离一些函数的这个技巧加速编译20次(并允许并行化它)。


Summary
This question is about achieving separate compilation of a single template class instantiation in a several different translation units.

Question
For non-template classes one can put definitions in several .cpp files and compile them separately. For instance:

file A.h:

class A {
public:
  void func1();
  void func2();
  void func3() { /* defined in class declaration */}
}

file A1.cpp:

void A::func1() { /* do smth */ }

file A2.cpp:

void A::func2() { /* do smth else */ }

Now I tried to do something similar with template classes. Since I know exactly which instances I will need, I'm explicitly instantiating templates. I'm compiling each instantiation separately, because member functions contain rather large mathematical expressions, which could slow down compiler considerably on high optimization levels. So I tried the following:

file TA.h:

template <typename T>
class TA {
public:
  void func1();
  void func2();
  void func3() { /* defined in class declaration */}
}

file TA1.cpp:

template <typename T>
void TA<T>::func1() { /* do smth */ }
template class TA<sometype>;

file TA2.cpp:

template <typename T>
void TA<T>::func2() { /* do smth else */ }
template class TA<sometype>;

It works with clang and GCC on Linux, but fails with GCC on Mac during linking during duplicate symbols error (in this example due to func3, which got instantiated in both TA1.cpp and TA2.cpp).

Then I stumbled upon this sentence in the standard:

C++11.14.7, paragraph 5:
For a given template and a given set of template-arguments,
-- an explicit instantiation definition shall appear at most once in a program,
-- ...

Does it mean that separate compilation of template classes is not possible (not allowed) even when using explicit instantiation (it is obviously not possible with implicit instantiation)?

PS I don't care since I've got my answer, but whoever thinks it is answered in here https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file is wrong.

解决方案

After another look at the standard, it seems to me that the only reasonable option is to use single explicit template class instantiation combined with explicit member function instantiations of a small number of "difficult" functions.

This (according to 14.7.2p9) will instantiate the class and all members which have been defined up to this point (which should include everything except "difficult" members). Then those selected members can be explicitly instantiated in other translation units containing their definitions.

That would make my example look like below (assuming that TA1.cpp contains easy functions and the only "difficult" function in TA is func2)

file TA1.cpp:

template <typename T>
void TA<T>::func1() { /* "simple" function definition */ }

template class TA<sometype>; /* expl. inst. of class */

file TA2.cpp:

template <typename T>
void TA<T>::func2() { /* "difficult" function definition */ }

template void TA<sometype>::func2(); /* expl. inst. of member */

This method requires us to write explicit instantiation definition for every "difficult" function, which is tedious but also makes us think twice whether we really want to keep it separately or not.

Disclaimer

When that can be useful? Not often. As other people here mentioned, it is not advised to split definitions of classes over several files. In my particular case "difficult" functions contain complicated mathematical operations on instances of non-trivial classes. C++ templates are not famous for fast compilation speeds, but in this case it was unbearable. These functions call each other which sends compiler on long and memory-consuming journey of expanding/inlining overloaded operators/templates/etc to optimize everything it sees, with pretty much zero improvement, but making compilation last for hours. This trick of isolating some functions in separate files speeds up compilation 20 times (and allows to parallelize it as well).

这篇关于单独编译和模板显式实例化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆