10
votes

Modèle de fonction dans un espace de noms dans un fichier distinct compile une amende, mais le lien de liaison ne peut pas le trouver

Ce problème consiste à définir et à déclarer un modèle de fonction dans un espace de noms défini dans un fichier externe à partir de laquelle la fonction est instanciée. Voici le plus petit exemple reproductible que je pourrais proposer. 4 Fichiers Suivre:

La déclaration de modèle de fonction dans un espace de noms nommé: xxx

la définition de modèle de fonction dans un fichier séparé: xxx

L'en-tête du programme principal xxx

enfin, le programme principal où le modèle de fonction est appelé: xxx

Je compile comme suit:

g ++ -c -o bar.o bar.cpp

g ++ -c -o foo. O FOO.CPP

Celles-ci fonctionnent bien. Maintenant, pour la liaison:

g ++ bar.o foo.o -o foobar

et l'erreur de compilateur résultante sur la référence non définie: < PRE> XXX

Il y a un problème évident avec le code qui ne se met pas disponible à partir de l'espace de noms ou dans la barre bar de la compilation.

En outre, lorsque j'essaie de placer la définition de dosomething dans la barre bar.h , comme je voudrais contourner les problèmes lors de la définition des méthodes de modèle de classe dans Séparez les fichiers .CPP, je reçois la même erreur.

Pouvez-vous perdre une erreur à mon compilateur d'erreur de liaison?


0 commentaires

4 Réponses :


3
votes

Mettre en place des définitions de modèles dans un fichier source distincte n'est pas bien supportée (je crois que le seul compilateur qui prend en charge Comeau).

Vous devez déplacer la définition dans vos fichiers d'en-tête: P>

// bar.h

namespace barspace {

  template <typename Iter>
    void DoSomething (Iter first, Iter last) {
      typedef typename std::iterator_traits<Iter>::value_type val_t;
      std::sort (first, last);
    }

} // namespace barspace


1 commentaires

Je comprends pourquoi la liaison a besoin de cela, mais cela ne vaingait pas tout le but d'avoir un fichier d'en-tête séparé?



1
votes

De nombreux compilateurs n'aiment pas que les fonctions de modèle définies dans des fichiers séparés. Placez toute la définition dans le fichier d'en-tête et il devrait compiler simplement bien.


0 commentaires

12
votes

Vous essayez de masquer la mise en œuvre de votre fonction modélise dans le fichier CPP, qui, malheureusement, n'est pas possible pour la plupart des compilateurs. Les fonctions / classes modèles sont instanciées lorsqu'elles sont utilisées, donc au point où vous appelez DOSOMOD "code>, le compilateur a besoin de la définition de la fonction pour pouvoir le compiler.

Il y a quelques solutions . P>

  1. Déplacez le corps de la fonction dans le fichier d'en-tête. Vous avez eu du mal à le faire avant, mais je dirais que cela est lié à autre chose. C'est l'approche préférée. P> LI>

  2. Inclure le fichier CPP de foo.cpp code>. (sauvage, mais pas que fort> rare). p> li>

  3. Instanciez le modèle de Double CODE>: P> LI> OL>

    // bar.cpp
    #include "bar.h"
    
    namespace barspace {
    
      template<>
        void DoSomething<double> (double first, double last) {
          typedef typename std::iterator_traits<double>::value_type val_t;
          std::sort (first, last);
        }
    
    } // namespace barspace
    


0 commentaires

1
votes

Vous devez définir des fonctions de modèle dans les en-têtes. Vous ne pouvez pas les déclarer, puis les définir dans un fichier de mise en œuvre; cela ne fonctionnera tout simplement pas. La raison est que le compilateur doit instancier les modèles avant de pouvoir les appeler. Pour instancier un modèle de fonction, le compilateur a besoin de deux choses:

  1. la définition de modèle
  2. Les paramètres de modèle pour instancier avec

    Dans votre cas, le compilateur fonctionne avec deux unités de compilation. Il peut bien les exécuter dans deux processus différents, de sorte que les unités de compilation sont indépendantes les unes des autres. Lorsque le compilateur compile Bar.cpp, il voit une définition de modèle sans demandes (appels) pour des instanciations spécifiques. Par conséquent, le compilateur n'instient pas le gabarit; Compiler Bar.CPP Rendements, en fait, rien. Le compilateur est suffisamment "intelligent" pour voir que vous n'avez pas besoin de ce modèle et l'optimise jusqu'à zéro surcharge.

    Bien sûr, vous avez besoin de ce modèle - dans FOO.CPP - mais c'est une unité de compilation différente, et maintenant, le compilateur a tout oublié (ou n'a pas encore appris) à propos de Bar.cpp. Le compilateur se trouve toutefois une déclaration de la fonction de modèle et rend l'hypothèse habituelle que si elle a été déclarée, elle a été définie (instanciée) ailleurs - et ne dit rien.

    Enfin, la liaison vient et obtient la vue ultime des oiseaux. Il peut voir qu'il n'y a pas de Dosomething (iter, iter) instancié pour std :: vecteur :: itérateur et se plaint.

    Il y a quelques solutions à votre problème. La meilleure solution consiste à utiliser le mot-clé exporter lorsque vous déclarez le modèle. Malheureusement, c'est aussi la pire solution, puisque la grande majorité des compilateurs ne prennent pas en charge cette fonctionnalité standard.

    Sérieusement, votre meilleur pari est de définir votre modèle dans le fichier d'en-tête. Ne le déclarez pas là-bas, définir là-bas. Vous n'aurez pas besoin de bar.cpp si c'est ce qu'il était pour la première place.


0 commentaires