Figure 1: modèles de fonction
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;
}
Est-ce la bonne façon d'utiliser extern template
, ou dois-je utiliser ce mot clé uniquement pour les modèles de classe comme dans la figure 2?
Figure 2: modèles de classe
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;
}
Je sais qu'il est bon de mettre tout cela dans un seul fichier d'en-tête, mais si nous instancions des modèles avec les mêmes paramètres dans plusieurs fichiers, nous avons alors plusieurs définitions identiques et le compilateur les supprimera toutes (sauf une) pour éviter les erreurs. Comment utiliser extern template
? Pouvons-nous l'utiliser uniquement pour les classes, ou pouvons-nous l'utiliser aussi pour les fonctions?
De plus, les figures 1 et 2 peuvent être développées en une solution dans laquelle les modèles sont dans un seul fichier d'en-tête. Dans ce cas, nous devons utiliser le extern template
mot - clé pour éviter plusieurs instanciations identiques. Est-ce uniquement pour les classes ou les fonctions?
extern template class foo<int>();
semble être une erreur.()
de la ligne externe. votre livre et votre studio visuel sont faux, essayez d'utiliser un compilateur plus conforme aux normes comme g ++ ou clang et vous verrez le problème.Réponses:
Vous ne devez utiliser
extern template
pour forcer le compilateur à ne pas instancier un modèle lorsque vous savez qu'il sera instancié ailleurs. Il est utilisé pour réduire le temps de compilation et la taille du fichier objet.Par exemple:
Cela entraînera les fichiers objets suivants:
Si les deux fichiers sont liés ensemble, l'un
void ReallyBigFunction<int>()
sera ignoré, ce qui entraînera une perte de temps de compilation et de taille de fichier objet.Pour ne pas perdre de temps de compilation et de taille de fichier objet, il existe un
extern
mot clé qui empêche le compilateur de compiler une fonction modèle. Vous devriez l'utiliser si et seulement si vous savez qu'il est utilisé dans le même binaire ailleurs.Changer
source2.cpp
pour:Donnera les fichiers objets suivants:
Lorsque les deux seront liés ensemble, le deuxième fichier objet utilisera simplement le symbole du premier fichier objet. Pas besoin de rejeter et pas de temps de compilation perdu ni de taille de fichier objet.
Cela ne doit être utilisé que dans un projet, comme lorsque vous utilisez un modèle
vector<int>
plusieurs fois, vous devez l'utiliserextern
dans tous les fichiers source sauf un.Cela s'applique également aux classes et aux fonctions comme des fonctions membres uniques et même de modèle.
la source
Wikipedia a la meilleure description
L'avertissement:
nonstandard extension used...
Microsoft VC ++ avait déjà une version non standard de cette fonctionnalité depuis quelques années (en C ++ 03). Le compilateur avertit à ce sujet pour éviter les problèmes de portabilité avec le code qui devait également être compilé sur différents compilateurs.
Regardez l'exemple dans la page liée pour voir qu'il fonctionne à peu près de la même manière. Vous pouvez vous attendre à ce que le message disparaisse avec les futures versions de MSVC, sauf bien sûr lors de l'utilisation d' autres extensions de compilateur non standard en même temps.
la source
std::vector
(presque sûr que toutes le font),extern
n'a aucun effet.extern template
n'est nécessaire que si la déclaration du modèle est complèteCela a été évoqué dans d'autres réponses, mais je ne pense pas qu'on y ait suffisamment insisté.
Cela signifie que dans les exemples OP, le
extern template
n'a aucun effet car les définitions de modèle sur les en-têtes étaient incomplètes:void f();
: juste déclaration, pas de corpsclass foo
: déclare la méthodef()
mais n'a pas de définitionJe recommanderais donc de supprimer simplement la
extern template
définition dans ce cas particulier: vous ne devez les ajouter que si les classes sont complètement définies.Par exemple:
TemplHeader.h
TemplCpp.cpp
Main.cpp
compilez et visualisez des symboles avec
nm
:production:
et puis à partir de
man nm
nous voyons que celaU
signifie indéfini, donc la définition n'est restée queTemplCpp
comme souhaité.Tout cela se résume au compromis des déclarations d'en-tête complètes:
extern template
chaque inclusion, ce que les programmeurs oublieront probablement de faireD'autres exemples de ceux-ci sont présentés à: Instanciation de modèle explicite - quand est-elle utilisée?
Étant donné que le temps de compilation est si critique dans les grands projets, je recommande vivement les déclarations de modèle incomplètes, à moins que des parties externes n'aient absolument besoin de réutiliser votre code avec leurs propres classes personnalisées complexes.
Et dans ce cas, j'essaierais d'abord d'utiliser le polymorphisme pour éviter le problème de temps de construction, et n'utiliserais des modèles que si des gains de performances notables peuvent être réalisés.
Testé dans Ubuntu 18.04.
la source
Le problème connu avec les modèles est le gonflement du code, qui est la conséquence de la génération de la définition de classe dans chaque module qui invoque la spécialisation du modèle de classe. Pour éviter cela, en commençant par C ++ 0x, on pourrait utiliser le mot-clé extern devant la spécialisation du modèle de classe
L'instanciation explicite de la classe de modèle ne doit se produire que dans une seule unité de traduction, de préférence celle avec la définition de modèle (MyClass.cpp)
la source
Si vous avez déjà utilisé extern pour les fonctions, la même philosophie est suivie pour les modèles. sinon, passer par extern pour des fonctions simples peut aider. En outre, vous souhaiterez peut-être placer le (s) externe (s) dans le fichier d'en-tête et inclure l'en-tête lorsque vous en avez besoin.
la source