Separate compilation and template instance creation

Summary
This issue is to achieve a separate compilation of one instance of the template class in several different translation units.

Question
For non-template classes, you can put the definitions in multiple .cpp files and compile them separately. For example:

Ah file:

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

A1.cpp file:

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

A2.cpp file:

 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 explicitly create the templates. I compile each instance separately, because member functions contain fairly large mathematical expressions that can significantly slow down the compiler at high levels of optimization. So I tried the following:

TA.h file:

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

TA1.cpp file:

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

TA2.cpp file:

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

It works with clang and GCC on Linux, but it doesnโ€™t work with GCC on Mac during binding during duplicate character errors (in this example, because of func3, which received an instance in both TA1.cpp and TA2.cpp).

Then I came across this sentence in the standard:

C ++ 11.14.7, paragraph 5:
For a given template and a given set of argument templates,
- the definition of an explicit instantiation should appear no more than once in the program,
-...

Does this mean that separate compilation of template classes is impossible (not allowed) even when using an explicit instance (this is clearly impossible with an implicit instance)?

PS I donโ€™t care, since I got my answer, but whoever thinks they are responding to this is https://stackoverflow.com/a/166129/

+2
c ++ templates explicit-instantiation
source share
2 answers

After another look at the standard, it seems to me that the only reasonable option is to use a single explicit instance of the template in combination with explicit instances of member functions of a small number of "difficult" functions.

This (according to 14.7.2p9) will create an instance of the class and all the members that were defined up to this point (which should include all but the "hard" members). Then these selected elements can be explicitly created in other translation units containing their definitions.

This will make my example look like this below (assuming TA1.cpp contains simple functions, and the only "hard" function in TA is func2 )

TA1.cpp file:

 template <typename T> void TA<T>::func1() { /* "simple" function definition */ } template class TA<sometype>; /* expl. inst. of class */ 

TA2.cpp file:

 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 an explicit definition of instantiation for each โ€œcomplexโ€ function, which is tedious, but also makes us think twice whether we want to keep it separate or not.

Renouncement

When can this be helpful? Infrequently. As mentioned above, it is not recommended to split class definitions across multiple files. In my particular case, "complex" functions contain complex mathematical operations on instances of nontrivial classes. C ++ templates are not known for fast compilation speed, but in this case it was unbearable. These functions call each other, which sends the compiler to a long and multi-user way of expanding / embedding overloaded operators / templates / etc to optimize everything that it sees with almost zero improvement, but the compilation lasts for hours. This trick for highlighting some functions in separate files speeds up compilation 20 times (and also allows you to parallelize it).

+1
source share

Separate compilation of templates is difficult, but allowed. What you cannot do is explicitly create an instance of the type in several translation units, just as you cannot define the same function in two translation units.

+1
source share

All Articles