2010-10-19 4 views
10

Ich möchte eine Bibliothek schreiben, die Sie verwenden müssen, müssen Sie nur eine Header-Datei enthalten. Wenn Sie jedoch mehrere Quelldateien haben und den Header in beide einschließen, erhalten Sie mehrere Definitionsfehler, da die Bibliothek sowohl deklariert als auch in der Kopfzeile definiert ist. Ich habe Header-Only-Bibliotheken gesehen, in Boost denke ich. Wie haben sie das gemacht?Header-only-Bibliotheken und mehrere Definitionsfehler

+0

verwenden Sie Wächter? EDIT: Sieh einen Blick auf Sams Antwort – smerlin

+0

@smerlin: Werfen Sie einen Blick auf die Kommentare zu Sams Antwort. – GManNickG

Antwort

21

Erklären Sie Ihre Funktionen inline, und sie in einem Namensraum setzen, so dass Sie nicht kollidieren:

namespace fancy_schmancy 
{ 
    inline void my_fn() 
    { 
    // magic happens 
    } 
}; 
+0

Aber wird es empfohlen, ** alle ** Funktionen 'inline' zu ​​machen, unabhängig von ihrer Natur? Ich dachte, nur "kurze" Funktionen sollten "inline" sein. – Arun

+5

Ignorieren Sie Ihre Professoren. Sie schreiben keinen Code für ihren Lebensunterhalt. "Nur kurze Funktionen sollten inline sein" ist eine Faustregel, aber es gibt so viele Ausnahmen und so viele andere wichtigere Gründe, warum Sie eine Funktion verwenden sollten oder sollten * nicht *, um die Faustregel fast nutzlos zu machen. –

+0

"Vorzeitige Mikro-Optimierung ist die Wurzel allen Übels" ist der erste Grund nicht inline zu sein, der mir in den Sinn kommt. –

2

-Boost nutzt Kopf nur viele Bibliotheken, weil wie die STL, ist es meist gebaut mit Klassen- und Funktionsschablonen , die fast immer nur Kopfzeilen sind.

Wenn Sie keine Vorlagen schreiben, würde ich vermeiden, Code in Ihre Header-Dateien aufzunehmen - es ist mehr Mühe als es wert ist. Mach das zu einer einfachen alten statischen Bibliothek.

0

Es gibt viele echte Header-only Boost-Bibliotheken, aber sie neigen dazu, sehr einfach zu sein (und/oder nur Vorlagen). Die größeren Bibliotheken erreichen den gleichen Effekt durch einige Tricks: Sie haben "automatische Verknüpfung" (Sie werden diesen Begriff here) sehen. Sie haben im Wesentlichen eine Reihe von Präprozessordirektiven in den Headern, die die entsprechende lib-Datei für Ihre Plattform ermitteln und eine #pragma verwenden, um den Linker anzuweisen, ihn zu verknüpfen. Sie müssen ihn also nicht explizit verknüpfen, aber er ist immer noch verlinkt.

+0

Wie verwenden Sie die automatische Verknüpfung in g ++? Ich weiß, in MSVC++ können Sie '#pragma (lib," blah.lib ") verwenden, aber wie machen Sie das gleiche mit g ++? – Epro

+0

@Epro: Ich fürchte, ich weiß nicht, wie es gemacht wird. Möglicherweise müssen Sie sich die Boost-Quelle ansehen. – rmeador

5

Der Hauptgrund, warum Boost hauptsächlich Header-only ist, ist, weil es stark Template-orientiert ist. Vorlagen erhalten im Allgemeinen einen Durchlauf von der Definitionsregel. Um Vorlagen effektiv zu verwenden, muss die Definition in jeder Übersetzungseinheit sichtbar sein, die die Vorlage verwendet.

Ein anderer Weg um die eine Definition Regel (ODR) ist inline Funktionen zu verwenden. Tatsächlich ist das, was inline wirklich macht, einen Freipass vom ODR zu bekommen - die Tatsache, dass es die Funktion inline ist, ist wirklich eher ein optionaler Nebeneffekt.

Eine letzte Option (aber wahrscheinlich nicht so gut) ist, Ihre Funktionen statisch zu machen. Dies kann zu einem aufgeblähten Code führen, wenn der Linker nicht in der Lage ist herauszufinden, dass alle diese Funktionsinstanzen wirklich identisch sind. Aber ich erwähne es aus Gründen der Vollständigkeit. Beachten Sie, dass Compiler häufig inline arbeiten static Funktionen, auch wenn sie nicht als inline markiert sind.

+0

Nun, die Boost-Dokumentation zitiert die Header-Only-Natur eines Großteils der Bibliothek als ein Merkmal. Und es sind nur die Dinge, die vernünftigerweise nicht nur Kopfzeile sein können (z. B. der regexp-Kram hat OS-Abhängigkeiten), der nicht nur Kopfzeile ist. Während einige Unter-Bibliotheken zweifellos nur Header sind, weil sie Template-Code sind, ist es falsch, diesen Grund Boost insgesamt zuzuschreiben, zumindest nach den Dokumenten. –