ChatGPT解决这个技术问题 Extra ChatGPT

using extern template (C++11)

Figure 1: function templates

TemplHeader.h

template<typename T>
void f();

TemplCpp.cpp

template<typename T>
void f(){
   //...
}    
//explicit instantation
template void f<T>();

Main.cpp

#include "TemplHeader.h"
extern template void f<T>(); //is this correct?
int main() {
    f<char>();
    return 0;
}

Is this the correct way to use extern template, or do I use this keyword only for class templates as in Figure 2?

Figure 2: class templates

TemplHeader.h

template<typename T>
class foo {
    T f();
};

TemplCpp.cpp

template<typename T>
void foo<T>::f() {
    //...
}
//explicit instantation
template class foo<int>;

Main.cpp

#include "TemplHeader.h"
extern template class foo<int>();
int main() {
    foo<int> test;
    return 0;
}

I know it is good to put all of this in one header file, but if we instantiate templates with the same parameters in multiple files, then we got multiple same definitions and the compiler will remove them all (except one) to avoid errors. How do I use extern template? Can we use it only for classes, or can we use it for functions too?

Also, Figure 1 and Figure 2 may be expanded to a solution where templates are in a single header file . In that case, we need to use the extern template keyword to avoid multiple same instantations. Is this only for classes or functions too?

This isn't the correct usage of extern templates at all... this doesn't even compile
Could you take some time to phrase the (one) question more clearly? What are you posting the code for? I don't see a question related to that. Also, extern template class foo<int>(); seems like a mistake.
@Dani> it compiles just fine on my visual studio 2010 except the warning message:Warning 1 warning C4231: nonstandard extension used : 'extern' before template explicit instantiation
@sehe question is very simple: how to, and when to use extern template keyword? (extern template is C++0x new future btw) you said "Also, extern template class foo(); seems like a mistake." no it is not, I have new C++ book and that's example from my book.
@codekiddy: then visual studio is really stupid.. in the second one the prototype doesn't match the implementation, and even if I fix that it says 'expected unqualified-id' near () on the extern line. both your book and visual studio are wrong, try to use more standard compliant compiler like g++ or clang and you will see the problem.

u
user1902689

You should only use extern template to force the compiler to not instantiate a template when you know that it will be instantiated somewhere else. It is used to reduce compile time and object file size.

For example:

// header.h

template<typename T>
void ReallyBigFunction()
{
    // Body
}

// source1.cpp

#include "header.h"
void something1()
{
    ReallyBigFunction<int>();
}

// source2.cpp

#include "header.h"
void something2()
{
    ReallyBigFunction<int>();
}

This will result in the following object files:

source1.o
    void something1()
    void ReallyBigFunction<int>()    // Compiled first time

source2.o
    void something2()
    void ReallyBigFunction<int>()    // Compiled second time

If both files are linked together, one void ReallyBigFunction<int>() will be discarded, resulting in wasted compile time and object file size.

To not waste compile time and object file size, there is an extern keyword which makes the compiler not compile a template function. You should use this if and only if you know it is used in the same binary somewhere else.

Changing source2.cpp to:

// source2.cpp

#include "header.h"
extern template void ReallyBigFunction<int>();
void something2()
{
    ReallyBigFunction<int>();
}

Will result in the following object files:

source1.o
    void something1()
    void ReallyBigFunction<int>() // compiled just one time

source2.o
    void something2()
    // No ReallyBigFunction<int> here because of the extern

When both of these will be linked together, the second object file will just use the symbol from the first object file. No need for discard and no wasted compile time and object file size.

This should only be used within a project, like in times when you use a template like vector<int> multiple times, you should use extern in all but one source file.

This also applies to classes and function as one, and even template member functions.


@Dani: the best explanation of extern templates I have read so far!
"if you know its used in the same binary somewhere else.". That is neither sufficient nor required. Your code is "ill-formed, no diagnostic required". You are not allowed to rely on an implicit instantiation of another TU (the compiler is allowed to optimize it away, much like an inline function). An explicit instantiation must be provided in another TU.
I would like to point out that this answer is probably wrong, and I got bitten by it. Luckily Johannes' comment had a number of up votes and I paid more attention to it this time around. I can only assume that the vast majority of voters on this question did not actually implement these types of templates in multiple compilation units (like I did today)... At least for clang, the only surefire way is to put these template definitions in your header! Be warned!
@JohannesSchaub-litb, could you elaborate a bit more or maybe provide a better answer? I'm not sure if I completely understood your objections.
Also, you can put the "extern template..." in "header.h", and make a "header.cpp" which explicitly instantiates it. "extern template" is defined to do nothing if it's along with an explicit instantiation. This at least works in gcc 7.2.0 and clang 5.0.0, I haven't used it yet in VS.
a
akim

Wikipedia has the best description

In C++03, the compiler must instantiate a template whenever a fully specified template is encountered in a translation unit. If the template is instantiated with the same types in many translation units, this can dramatically increase compile times. There is no way to prevent this in C++03, so C++11 introduced extern template declarations, analogous to extern data declarations. C++03 has this syntax to oblige the compiler to instantiate a template: template class std::vector; C++11 now provides this syntax: extern template class std::vector; which tells the compiler not to instantiate the template in this translation unit.

The warning: nonstandard extension used...

Microsoft VC++ used to have a non-standard version of this feature for some years already (in C++03). The compiler warns about that to prevent portability issues with code that needed to compile on different compilers as well.

Look at the sample in the linked page to see that it works roughly the same way. You can expect the message to go away with future versions of MSVC, except of course when using other non-standard compiler extensions at the same time.


tnx for your reply sehe, so what this acctualy means is that "extern template" future fully works for VS 2010 and we can just ignore the warning? (using pragma to ignore the message for example) and be shore that template is not instantiated more then on time in VSC++. compiler. thanks.
"... which tells the compiler not to instantiate the template in this translation unit." I don't think this is true. Any method defined in the class definition counts as inline, so if the STL implementation uses inline methods for std::vector (pretty sure all of them do), extern has no effect.
Yep, this answer is misleading. MSFT doc: "The extern keyword in the specialization only applies to member functions defined outside of the body of the class. Functions defined inside the class declaration are considered inline functions and are always instantiated." All STL classes in VS (last checked was 2017) have only inline methods unfortunately.
That goes for all inline declarations regardless of where they arise, always @0kcats
@sehe The reference to Wiki with std::vector example and a reference to MSVC in the same answer makes one believe that there might be some benefit in using extern std::vector in MSVC, while there is no so far. Not sure if this is requirement of the standard, maybe other compilers have same issue.
C
Ciro Santilli Путлер Капут 六四事

extern template is only needed if the template declaration is complete

This was hinted at in other answers, but I don't think enough emphasis was given to it.

What this means is that in the OP's examples, the extern template has no effect because the template definitions on the headers were incomplete:

void f();: just declaration, no body

class foo: declares method f() but has no definition

So I would recommend just removing the extern template definition in that particular case: you only need to add them if the classes are completely defined.

For example:

TemplHeader.h

template<typename T>
void f();

TemplCpp.cpp

template<typename T>
void f(){}

// Explicit instantiation for char.
template void f<char>();

Main.cpp

#include "TemplHeader.h"

// Commented out from OP code, has no effect.
// extern template void f<T>(); //is this correct?

int main() {
    f<char>();
    return 0;
}

compile and view symbols with nm:

g++ -std=c++11 -Wall -Wextra -pedantic -c -o TemplCpp.o TemplCpp.cpp
g++ -std=c++11 -Wall -Wextra -pedantic -c -o Main.o Main.cpp
g++ -std=c++11 -Wall -Wextra -pedantic -o Main.out Main.o TemplCpp.o
echo TemplCpp.o
nm -C TemplCpp.o | grep f
echo Main.o
nm -C Main.o | grep f

output:

TemplCpp.o
0000000000000000 W void f<char>()
Main.o
                 U void f<char>()

and then from man nm we see that U means undefined, so the definition did stay only on TemplCpp as desired.

All this boils down to the tradeoff of complete header declarations:

upsides: allows external code to use our template with new types we have the option of not adding explicit instantiations if we are fine with object bloat

allows external code to use our template with new types

we have the option of not adding explicit instantiations if we are fine with object bloat

downsides: when developing that class, header implementation changes will lead smart build systems to rebuild all includers, which could be many many files if we want to avoid object file bloat, we need not only to do explicit instantiations (same as with incomplete header declarations) but also add extern template on every includer, which programmers will likely forget to do

when developing that class, header implementation changes will lead smart build systems to rebuild all includers, which could be many many files

if we want to avoid object file bloat, we need not only to do explicit instantiations (same as with incomplete header declarations) but also add extern template on every includer, which programmers will likely forget to do

Further examples of those are shown at: Explicit template instantiation - when is it used?

Since compilation time is so critical in large projects, I would highly recommend incomplete template declarations, unless external parties absolutely need to reuse your code with their own complex custom classes.

And in that case, I would first try to use polymorphism to avoid the build time problem, and only use templates if noticeable performance gains can be made.

Tested in Ubuntu 18.04.


M
Marek R

The known problem with the templates is code bloating, which is consequence of generating the class definition in each and every module which invokes the class template specialization. To prevent this, starting with C++0x, one could use the keyword extern in front of the class template specialization

#include <MyClass>
extern template class CMyClass<int>;

The explicit instantion of the template class should happen only in a single translation unit, preferable the one with template definition (MyClass.cpp)

template class CMyClass<int>;
template class CMyClass<float>;

q
qqqqq

If you have used extern for functions before, exactly same philosophy is followed for templates. if not, going though extern for simple functions may help. Also, you may want to put the extern(s) in header file and include the header when you need it.