Clang ++ lässt Linker in Vorlagenklassen fehlschlagen (funktioniert aber mit g ++)

Dec 23 2020

Ich habe ein Programm, das gut mit GCC funktioniert, aber wenn ich es stattdessen mit Clang kompiliere, schlägt der Linker fehl.

Ich denke, mein Problem sind Vorlagenklassen, deshalb habe ich dieses kleine Beispiel implementiert.

test.cpp::

#include "Point.h"

int main()
{
    Point<int> p1;
    Point<int> p2{ 3, 6 };
}

Point.h::

#ifndef POINT_H
#define POINT_H

template<typename T>
class Point {
    T x, y;
  public:
    Point();
    Point(T, T);
};

template class Point<int>;
template class Point<float>;

#endif

Point.cpp::

#include "Point.h"

template<typename T>
Point<T>::Point()
    : x{0}, y{0}
{}

template<typename T>
Point<T>::Point(T t_x, T t_y)
    : x{t_x}, y{t_y}
{}

Wenn ich es mit baue g++ Point.cpp test.cpp, funktioniert es ohne Probleme.

Bei Clang treten jedoch die folgenden Fehler auf:

$ clang++ Point.cpp test.cpp
/usr/bin/ld: /tmp/test-8ab886.o: in function `main':
test.cpp:(.text+0x1a): undefined reference to `Point<int>::Point()'
/usr/bin/ld: test.cpp:(.text+0x2d): undefined reference to `Point<int>::Point(int, int)'
clang-11: error: linker command failed with exit code 1 (use -v to see invocation)

Oder mit lld:

$ clang++ -fuse-ld=lld Point.cpp test.cpp
ld.lld: error: undefined symbol: Point<int>::Point()
>>> referenced by test.cpp
>>>               /tmp/test-f95759.o:(main)

ld.lld: error: undefined symbol: Point<int>::Point(int, int)
>>> referenced by test.cpp
>>>               /tmp/test-f95759.o:(main)
clang-11: error: linker command failed with exit code 1 (use -v to see invocation)

Ich denke, meine expliziten Instanziierungen in Point.hsind nicht gut genug für Clang, aber ich kann mir nicht vorstellen, was es will.

Antworten

5 Jarod42 Dec 23 2020 at 07:17

Ihre explizite Instanziierung sollte dort sein, wo Definitionen sichtbar sind, also am Ende von Points.cpp

Von class_template # Explicit_instantiation :

Eine explizite Instanziierungsdefinition erzwingt die Instanziierung der Klasse, Struktur oder Vereinigung, auf die sie sich beziehen. Es kann an einer beliebigen Stelle nach der Vorlagendefinition im Programm erscheinen und darf für eine bestimmte Argumentliste nur einmal im gesamten Programm erscheinen, ohne dass eine Diagnose erforderlich ist.