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?
Était-ce utile?

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top