2009-03-05 13 views
3

Je dois écrire une fonction en C replace_all basé sur un modèle ++ qui prendra une chaîne, wstring, glibmm :: ustring etc., et remplacer toutes les occurrences de search dans subject avec replace.référence non définie à fonctionner modèle lorsqu'il est utilisé avec la chaîne (GCC)

replace_all.cc

template < class T > 
T replace_all(
     T const &search, 
     T const &replace, 
     T const &subject 
) { 
     T result; 

     typename T::size_type done = 0; 
     typename T::size_type pos; 
     while ((pos = subject.find(search, done)) != T::npos) { 
       result.append (subject, done, pos - done); 
       result.append (replace); 
       done = pos + search.size(); 
     } 
     result.append(subject, done, subject.max_size()); 
     return result; 
} 

test.cc

#include <iostream> 

template < class T > 
T replace_all(
     T const &search, 
     T const &replace, 
     T const &subject 
); 

// #include "replace_all.cc" 

using namespace std; 

int main() 
{ 
     string const a = "foo bar fee boor foo barfoo b"; 
     cout << replace_all<string>("foo", "damn", a) << endl; 
     return 0; 
} 

Lorsque je tente de compiler ce gcc 4.1.2

g++ -W -Wall -c replace_all.cc 
g++ -W -Wall -c test.cc 
g++ test.o replace_all.o 

Je reçois:

test.o: In function `main': 
test.cc:(.text+0x13b): undefined reference to ` 
    std::basic_string<char, std::char_traits<char>, std::allocator<char> > 
    replace_all< std::basic_string<char, std::char_traits<char>, std::allocator<char> > >(
     std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, 
     std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, 
     std::basic_string<char, std::char_traits<char>, std::allocator<char> > const& 
    ) 
' 
collect2: ld returned 1 exit status 

Mais quand je décommenter #include "replace_all.cc" dans test.cc et compilent ainsi:

g++ -W -Wall test.cc 

Les liens du programme et produit attendu sortie:

damn bar fee boor damn bardamn b 

Pourquoi liaison échoue et que puis-je faire pour le faire fonctionner ?

Répondre

8

Vous ne pouvez pas lier les modèles car le compilateur ne sait pas quel code générer avant que quelqu'un ne tente d'utiliser (instancier) des modèles.

Vous pouvez demander au compilateur d'instancier un modèle si vous connaissez les types que vous allez utiliser ou si vous savez qu'ils sont limités.
Si vous voulez - mettre ceci à votre fichier .cc:

template std::string replace_all(std::string const& search, 
            std::string const& replace, 
            std::string const& subject); 


template glibmm::ustring replace_all(glibmm::ustring const& search, 
             glibmm::ustring const& replace, 
             glibmm::ustring const& subject); 
6

Le compilateur doit voir la définition du modèle au moment de l'instanciation, sinon le code spécialisé pour le type avec lequel vous instanciez le modèle ne peut pas être généré. La bonne façon est de mettre l'implémentation des fonctions du template in the header file or to #include the .cc comme vous l'avez fait.