Wenn ich eine spezielle Vorlage in verschiedenen Objektdateien verwende, wird beim Verknüpfen ein Fehler "Mehrfachdefinition" angezeigt. Die einzige Lösung, die ich gefunden habe, ist die Verwendung der "Inline" -Funktion, aber es scheint nur eine Problemumgehung zu sein. Wie löse ich das, ohne das Schlüsselwort "inline" zu verwenden? Wenn das nicht möglich ist, warum?
Hier ist der Beispielcode:
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
Schließlich:
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
Wenn ich das "Inline" in hello.h auskommentiere, wird der Code kompiliert und ausgeführt, aber das scheint mir nur eine Art "Problemumgehung" zu sein: Was ist, wenn die spezialisierte Funktion groß ist und oft verwendet wird? Bekomme ich eine große Binärdatei? Gibt es eine andere Möglichkeit, dies zu tun? Wenn ja, wie? Wenn nicht, warum?
Ich habe versucht, nach Antworten zu suchen, aber alles, was ich bekam, war "Inline verwenden" ohne weitere Erklärung.
Vielen Dank
Antworten:
Wenn Sie etwas vollständig spezialisieren, hängt es intuitiv nicht mehr von einem Vorlagenparameter ab. Wenn Sie die Spezialisierung nicht inline durchführen, müssen Sie sie in eine CPP-Datei anstatt in eine .h-Datei einfügen, oder Sie verletzen am Ende die eine Definitionsregel, wie David sagt. Beachten Sie, dass beim teilweisen Spezialisieren von Vorlagen die teilweisen Spezialisierungen immer noch von einem oder mehreren Vorlagenparametern abhängen, sodass sie weiterhin in einer .h-Datei gespeichert werden.
quelle
hello.h
.template <typename T>
ein Headertemplate<>
angezeigt wird, wird dies möglicherweise nicht der Fall sein.Bei dem Schlüsselwort
inline
geht es mehr darum, dem Compiler mitzuteilen, dass das Symbol in mehr als einer Objektdatei vorhanden ist, ohne die One Definition-Regel zu verletzen, als um das tatsächliche Inlining, das der Compiler entscheiden kann oder nicht.Das Problem, das Sie sehen, ist, dass die Funktion ohne Inline in allen Übersetzungseinheiten kompiliert wird, die den Header enthalten, was gegen die ODR verstößt. Hinzu
inline
kommt der richtige Weg. Andernfalls können Sie die Spezialisierung weiterleiten und in einer einzigen Übersetzungseinheit bereitstellen, wie Sie es bei jeder anderen Funktion tun würden.quelle
Sie haben eine Vorlage in Ihrem Header explizit instanziiert (
void Hello<T>::print_hello(T var)
) . Dadurch werden mehrere Definitionen erstellt. Sie können es auf zwei Arten lösen:1) Machen Sie Ihre Instanziierung inline.
2) Deklarieren Sie die Instanziierung in einem Header und implementieren Sie sie dann in einem CPP.
quelle
Hier finden Sie einige Stück von C ++ 11 - Standard zu diesem Problem:
Wenn Sie also einige explizite (auch als vollständige) Spezialisierungen von Vorlagen in
*.h
Dateien vornehmen , müssen Sie trotzdeminline
helfen, die Verletzung von ODR zu beseitigen .quelle