Plusieurs définitions d'un modèle de fonction
Question
Supposons qu'un fichier d'en-tête définit un modèle de fonction. Supposons maintenant deux fichiers d'implémentation #include
dans cet en-tête, et chacun d'eux appelle le modèle de fonction. Dans les deux fichiers d'implémentation, le modèle de fonction est instancié avec le même type.
// header.hh
template <typename T>
void f(const T& o)
{
// ...
}
// impl1.cc
#include "header.hh"
void fimpl1()
{
f(42);
}
// impl2.cc
#include "header.hh"
void fimpl2()
{
f(24);
}
On peut s’attendre à ce que l’éditeur de liens se plaint de plusieurs définitions de f ()
. Plus précisément, si f ()
ne serait pas un modèle, ce serait effectivement le cas.
- Comment se fait-il que l'éditeur de liens ne se plaint pas de plusieurs définitions de
f ()
? - La norme spécifie-t-elle que l'éditeur de liens doit gérer cette situation avec élégance? En d’autres termes, puis-je toujours compter sur des programmes similaires à ce qui précède pour compiler et lier?
- Si l'éditeur de liens peut être assez intelligent pour désambiguïser un ensemble d'instanciations de modèles de fonctions, pourquoi ne peut-il pas en faire autant pour les fonctions standard, étant donné qu'elles sont identiques à celles utilisées pour les modèles de fonctions instanciées?
La solution
Pour prendre en charge le langage C ++, l'éditeur de liens est suffisamment intelligent pour reconnaître qu'il s'agit de la même fonction et rejette tous les éléments sauf un.
EDIT: clarification: L'éditeur de liens ne compare pas le contenu des fonctions et ne détermine pas qu'elles sont identiques. Les fonctions modèles sont marquées comme telles et l'éditeur de liens reconnaît qu'elles possèdent les mêmes signatures.
Autres conseils
Le manuel du compilateur Gnu C ++ contient une bonne discussion à ce sujet . . Un extrait:
Les modèles C ++ sont la première langue fonctionnalité pour exiger plus d'intelligence de l'environnement que d'habitude trouve sur un système UNIX. En quelque sorte le le compilateur et l'éditeur de liens doivent s'assurer que que chaque instance de modèle se produit exactement une fois dans l'exécutable si est nécessaire, et pas du tout autrement. Il existe deux approches de base à cette problème, qui sont appelés le Le modèle de Borland et le modèle de Cfront.
modèle de Borland
Borland C ++ a résolu le modèle. problème d'instanciation en ajoutant le équivalent de code des blocs communs à leur lieur; le compilateur émet instances de modèles dans chaque traduction unité qui les utilise, et l'éditeur de liens les effondre ensemble. L'avantage de ce modèle est que l'éditeur de liens seulement doit considérer les fichiers objets se; il n'y a pas externe complexité à s'inquiéter. Ce inconvénient est que le temps de compilation est augmenté parce que le code du modèle est en cours de compilation à plusieurs reprises. Code écrit pour ce modèle a tendance à inclure les définitions de tous les modèles dans le fichier d'en-tête, car ils doivent être vu pour être instancié.
Modèle Cfront
Le traducteur AT & T C ++, Cfront, résolu l'instanciation du template problème en créant la notion de référentiel de modèles, un endroit maintenu où modèle les instances sont stockées. Un plus moderne la version du référentiel fonctionne comme suit: sous forme de fichiers d'objets individuels sont construits, le compilateur place tout définitions de modèles et instanciations rencontrées dans le dépôt. Au moment du lien, le lien wrapper ajoute dans les objets dans le référentiel et compile si nécessaire cas qui n'étaient pas auparavant émis. Les avantages de ce modèle sont la vitesse de compilation plus optimale et la possibilité d'utiliser l'éditeur de liens du système; mettre en œuvre le modèle de Borland un fournisseur du compilateur doit également remplacer le lieur. Les inconvénients sont complexité considérablement accrue, et donc potentiel d'erreur; pour du code cela peut être tout aussi transparent, mais en pratique, cela peut être très difficile construire plusieurs programmes en un répertoire et un programme sur plusieurs des répertoires. Code écrit pour cela modèle tend à séparer les définitions de modèles de membre non en ligne dans un fichier séparé, qui devrait être compilé séparément.
Utilisé avec GNU ld version 2.8 ou plus tard sur un système ELF tel que GNU / Linux ou Solaris 2, ou sur Microsoft Windows, G ++ prend en charge le Modèle de Borland. Sur d'autres systèmes, G ++ n'implémente ni le modèle automatique.
Il s’agit plus ou moins d’un cas particulier pour les modèles.
Le compilateur ne génère que les instanciations de modèles réellement utilisées. Comme il n'a aucun contrôle sur le code qui sera généré à partir d'autres fichiers sources, il doit générer le code de modèle une fois pour chaque fichier, afin de s'assurer que la méthode est générée.
Comme il est difficile de résoudre ce problème (la norme comporte un mot clé extern
pour les modèles, mais g ++ ne le met pas en œuvre), l'éditeur de liens accepte simplement les définitions multiples.