2017-07-27 1 views
2

Ich habe ein sehr seltsames Problem mit dem GCC 5.4.0 Linker. Ich habe diese Dateien:Header-only-Klasse + Undefinierter Verweis auf Funktion NUR WENN Rückgabeobjekt dieser Klasse

spline.h, utils.h/cpp, main.cpp

spline.h ist ein Kopf nur Utility-Klasse für Befestigungspunkte auf Splines.

1) Ich erstelle eine Bibliothek mit utils.cpp und CMake:

add_library(utils_lib utils.cpp) 

utils.h#include ist spline.h ing.

2) Ich eröffne mein binär aus main.cpp:

add_executable(hello_world main.cpp) 
target_link_libraries(hello_world utils_lib) 

3) Innerhalb utils.cpp, ich habe diese Funktion:

tk::spline fitSpline(const std::vector<double>& x, 
        const std::vector<double>& y) 
{ 
    tk::spline output; 
    output.set_points(x,y); 
    return output; 
} 

Also, wenn ich versuche, diese Funktion innerhalb main.cpp zu verwenden:

auto my_spline = fitSpline(x,y); 

Dann bekomme ich diesen Linker Fehler:

undefined reference to `fitSpline(std::vector<double, std::allocator<double> > const&, std::vector<double, std::allocator<double> > const&)' 

Allerdings, wenn ich den Rückgabewert von fitSpline-double zum Beispiel ändern:

double fitSpline(const std::vector<double>& x, 
       const std::vector<double>& y) 
{ 
    tk::spline output; 
    output.set_points(x,y); 

    return 0.0; 
} 

Dann mehr ich nicht die Linker-Fehler erhalten! Es kompiliert einfach gut. Ich verstehe wirklich nicht, was das Problem ist, irgendwelche Hinweise?

Danke!

+0

Gibt es eine vorhandene Funktionssignatur für 'fitSpline' in' utils.h'? Nur das, was mir gerade einfällt. Wenn möglich, poste den entsprechenden Code in 'utils. *' Und 'main.cpp'. – hnefatl

+0

@hnefatl Ja, die Signatur ist da. Wie ich schon sagte, wenn ich nur den Rückgabewerttyp ändere, funktioniert alles gut. Ich habe gerade festgestellt, dass "spline.h" alles in einem anonymen Namensraum hat, sicher muss das der Grund sein! Muss ich es dann in jede cpp-Datei aufnehmen? – user1011113

+0

Wenn sie wirklich in einem [anonymen Namespace] sind (https://stackoverflow.com/questions/154469/unnamed-anonymous-namespaces-vs-static-functions), sollte nichts außerhalb der Datei auf sie zugreifen können. Mit Signatur wollte ich fragen, ob Sie eine Split-Definition und Implementierung der Funktion hatten, und vergessen, eines von ihnen zu aktualisieren. Ein 'spline.h' in' main.cpp' könnte helfen, aber ich kann nicht wirklich herausfinden warum. Das Posten von mehr Code würde helfen. – hnefatl

Antwort

0

Es gibt zwei Übersetzungseinheiten. Die TU für utils_lib und die TU für main.cpp.

Namen in unbenannten Namespaces befinden sich beide in einem eindeutigen Namespace UND haben effektiv eine interne Verknüpfung (seit C++ 11 sind sie als interne Verknüpfung definiert).

So wird der Versuch, einen Typ wie tk::spline von einer anderen TU zu referenzieren, aufgrund der effektiven internen Verknüpfung fehlschlagen.

Duplizieren Verwendung von spline.h wäre normalerweise in Ordnung, wenn die Objekte zustandslos und nicht freigegeben waren. Aber hier machst du das nicht. Sie behandeln sie als fungibel, indem Sie ein Objekt in einer TU erstellen und versuchen, sie über einen Typ in einer anderen TU zu speichern. Dies schlägt fehl, weil sie unterschiedliche eindeutige Namespace-Namen haben.

Wenn Sie wirklich keine unnötigen Symbole in eine Nur-Header-Bibliothek exportieren möchten, sollten Sie nur für diese Symbole einen internen "Detail" -Namespace verwenden, während diejenigen, die Benutzern im äußeren Namespace bekannt sein sollten .

Nichts davon, btw, hat etwas mit cmake oder einem Build-System zu tun. Da jedoch Ihre Frage cmake verwendet, um die Struktur viel klarer zu machen (gute Arbeit btw), ist das Tag wahrscheinlich in Ordnung.

Verwandte Themen