Lorsque j'utilise un modèle spécialisé dans différents fichiers objets, j'obtiens une erreur de «définition multiple» lors de la liaison. La seule solution que j'ai trouvée consiste à utiliser la fonction "en ligne", mais cela semble être une solution de contournement. Comment résoudre ce problème sans utiliser le mot clé "inline"? Si ce n'est pas possible, pourquoi?
Voici l'exemple de code:
paulo@aeris:~/teste/cpp/redef$ cat hello.h
#ifndef TEMPLATE_H
#define TEMPLATE_H
#include <iostream>
template <class T>
class Hello
{
public:
void print_hello(T var);
};
template <class T>
void Hello<T>::print_hello(T var)
{
std::cout << "Hello generic function " << var << "\n";
}
template <> //inline
void Hello<int>::print_hello(int var)
{
std::cout << "Hello specialized function " << var << "\n";
}
#endif
paulo@aeris:~/teste/cpp/redef$ cat other.h
#include <iostream>
void other_func();
paulo@aeris:~/teste/cpp/redef$ cat other.c
#include "other.h"
#include "hello.h"
void other_func()
{
Hello<char> hc;
Hello<int> hi;
hc.print_hello('a');
hi.print_hello(1);
}
paulo@aeris:~/teste/cpp/redef$ cat main.c
#include "hello.h"
#include "other.h"
int main()
{
Hello<char> hc;
Hello<int> hi;
hc.print_hello('a');
hi.print_hello(1);
other_func();
return 0;
}
paulo@aeris:~/teste/cpp/redef$ cat Makefile
all:
g++ -c other.c -o other.o -Wall -Wextra
g++ main.c other.o -o main -Wall -Wextra
Finalement:
paulo@aeris:~/teste/cpp/redef$ make
g++ -c other.c -o other.o -Wall -Wextra
g++ main.c other.o -o main -Wall -Wextra
other.o: In function `Hello<int>::print_hello(int)':
other.c:(.text+0x0): multiple definition of `Hello<int>::print_hello(int)'
/tmp/cc0dZS9l.o:main.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status
make: ** [all] Erro 1
Si je décommente le "inline" dans hello.h, le code se compilera et s'exécutera, mais cela me semble être une sorte de "contournement": et si la fonction spécialisée est volumineuse et utilisée plusieurs fois? Vais-je avoir un gros binaire? Y a-t-un autre moyen de faire ça? Si oui, comment? Si non, pourquoi?
J'ai essayé de chercher des réponses, mais tout ce que j'ai obtenu était "utiliser en ligne" sans aucune autre explication.
Merci
Réponses:
Intuitivement, lorsque vous spécialisez complètement quelque chose, cela ne dépend plus d'un paramètre de modèle - donc à moins que vous ne fassiez la spécialisation en ligne, vous devez le mettre dans un fichier .cpp au lieu d'un .h ou vous finissez par violer le une règle de définition comme le dit David. Notez que lorsque vous spécialisez partiellement les modèles, les spécialisations partielles dépendent toujours d'un ou plusieurs paramètres de modèle, elles sont donc toujours placées dans un fichier .h.
la source
hello.h
.template <typename T>
elle peut entrer dans un en-tête, et si c'est le cas, ce n'esttemplate<>
peut-être pas le cas?Le mot
inline
- clé consiste davantage à indiquer au compilateur que le symbole sera présent dans plusieurs fichiers objets sans violer la règle d'une définition qu'à une insertion réelle, ce que le compilateur peut décider de faire ou de ne pas faire.Le problème que vous voyez est que sans l'inline, la fonction sera compilée dans toutes les unités de traduction qui incluent l'en-tête, violant l'ODR. L'ajout
inline
est la bonne voie à suivre. Sinon, vous pouvez transmettre la déclaration de spécialisation et la fournir dans une seule unité de traduction, comme vous le feriez avec n'importe quelle autre fonction.la source
Vous avez explicitement instancié un modèle dans votre en-tête (
void Hello<T>::print_hello(T var)
). Cela créera plusieurs définitions. Vous pouvez le résoudre de deux manières:1) Créez votre instanciation en ligne.
2) Déclarez l'instanciation dans un en-tête, puis implémentez-la dans un cpp.
la source
Voici une partie de la norme C ++ 11 liée à ce problème:
Donc, si vous effectuez des spécialisations explicites (c'est-à-dire complètes) de modèles dans un
*.h
fichier, vous devrez toujoursinline
vous aider à vous débarrasser de la violation de l' ODR .la source