2017-05-20 1 views
4

J'ai une classe de template "Extra", définie dans "extra.h", avec une fonction "doSomething", et j'ai défini deux spécialisations de "doSomething". Deux fonctions différentes créent des objets de type "Extra", chacun avec un paramètre de type différent, et chacun d'eux appelle une autre des spécialisations. Les deux fonctions client "client1" et "client2" sont définies dans deux fichiers, "client1.cpp" et "client2.cpp" respectivement. Dans un troisième fichier, "principal" appelle "client1" puis "client2". Maintenant, "client1.cpp" et "client2.cpp" les deux #include "extra.h". J'obtiens une erreur de linker que "doSomething" a (2) plusieurs définitions. Naturellement, si je mets les définitions de "client1" et "client2" dans un seul fichier source, je n'ai pas ce problème. Est-il possible que je puisse conserver mon arrangement de fichiers distincts pour "client1" et "client2"? Voici mon code. Je vous remercie!Définitions de spécialisation de modèle C++ partagées entre les fichiers

// extra.h 
#ifndef EXTRA_H 
#define EXTRA_H 

template <typename T> 
class Extra 
{ 
    public: 
     Extra(T); 
     ~Extra(); 
     T doSomething(T); 
    private: 
     Extra() {} 
     T m_value; 
}; 

template <typename T> Extra<T>::Extra(T input) : m_value{input} {} 

template <typename T> Extra<T>::~Extra() {} 

template <> int Extra<int>::doSomething(int input) 
{ 
    return input * m_value; 
} 

template <> double Extra<double>::doSomething(double input) 
{ 
    return input + m_value; 
} 

template <typename T> T Extra<T>::doSomething(T input) 
{ 
    return input; 
} 
#endif 

// client1.cpp 
#include "extra.h" 
#include <iostream> 

void client1() 
{ 
    std::cout << "In client1." << std::endl; 
    Extra<int> extra(2); 
    int res = extra.doSomething(3); 
    std::cout << "Value: " << res << std::endl; 
} 

// client2.cpp 
#include "extra.h" 
#include <iostream> 

void client2() 
{ 
    std::cout << "In client2." << std::endl; 
    Extra<double> extra(2.0); 
    double res = extra.doSomething(2.0); 
    std::cout << "Value: " << res << std::endl; 
} 

// main.cpp 
#include <iostream> 

void client1(); 
void client2(); 

int main() 
{ 
    std::cout << "In main." << std::endl; 
    client1(); 
    client2(); 
    return 0; 
} 

Et ici, pour complétude, est mon erreur d'éditeur de liens:

$ g++ -std=c++11 -o client client1.cpp client2.cpp main.cpp 
duplicate symbol __ZN5ExtraIiE11doSomethingEi in: 
    /var/folders/mf/jdvfkpms609206zpz8x5237r0000gn/T/client1-6fa7ed.o 
    /var/folders/mf/jdvfkpms609206zpz8x5237r0000gn/T/client2-387444.o 
duplicate symbol __ZN5ExtraIdE11doSomethingEd in: 
    /var/folders/mf/jdvfkpms609206zpz8x5237r0000gn/T/client1-6fa7ed.o 
    /var/folders/mf/jdvfkpms609206zpz8x5237r0000gn/T/client2-387444.o 
ld: 2 duplicate symbols for architecture x86_64 

Répondre

3

Vous devez marquer votre doSomething en ligne:

template <> inline int Extra<int>::doSomething(int input) 
{ 
    return input * m_value; 
} 

template <> inline double Extra<double>::doSomething(double input) 
{ 
    return input + m_value; 
} 
+0

Merci beaucoup! J'avais déjà essayé - pensais-je - mais j'avais oublié que vous deviez marquer les définitions _inline_ et pas seulement la déclaration. –

+0

@AmittaiAviram avec ce problème solution proposée est fixe, non? – Pavel

+0

Oui! Maintenant, c'était un exemple de jouet, bien sûr, donc je dois essayer de l'appliquer au cas réel, ce qui est beaucoup plus compliqué. Je suppose que le principe général est que vous devez intégrer chaque spécialisation de fonction, de sorte que le compilateur déplace le code dans l'appelant, et il n'apparaîtra plus comme une définition de fonction distincte dans plusieurs unités de traduction. Merci encore! –