Bedeutung einer INL-Datei in C ++

108

Was sind die Vorteile von Deklarationen in einer INL-Datei? Wann müsste ich das gleiche verwenden?

Zuzu
quelle
3
FWIW, ich hasse .inl-Dateien. Warum sollten Sie Ihren Code mehr als nötig aufteilen?
Shog9
10
@ shog9: Schnittstelle von der Implementierung trennen. Ich habe C # - und Java-Dateien immer gehasst, weil es so schwierig ist, die Benutzeroberfläche zu lesen, weil alle Details der messey-Implementierung vorhanden sind.
Martin York
8
@Martin - leider bietet C ++ eine schlechte Kombination beider Welten - die Schnittstelle und einen Teil der Implementierung im Header, den Rest der Implementierung in der CPP-Datei. Selbst wenn Sie Inline-Funktionen vermeiden (oder sie in INL-Dateien ablegen), müssen Sie die Benutzeroberfläche mit den lästigen Details privater Mitglieder überladen, es sei denn, Sie können das Pimpl-Idiom religiös verwenden.
Michael Burr
5
Ja, ich habe das Argument, dass Header die Schnittstelle von der Implementierung trennen, nie verstanden. Sie tun es offensichtlich nicht. Eine Schnittstelle sollte nicht alle privaten Mitglieder enthalten.
Jalf
@LokiAstari: Um fair zu sein, verfügt Java / C # über sehr gute Tools, die die Schnittstellenübersicht automatisch bereitstellen. Man könnte es anders herum sagen: In C ++ müssen Sie ein Problem manuell lösen, das von Computern vollständig gelöst werden kann.
bluenote10

Antworten:

139

.inlDateien sind niemals obligatorisch und haben für den Compiler keine besondere Bedeutung. Es ist nur eine Möglichkeit, Ihren Code zu strukturieren, die den Menschen, die ihn lesen könnten, einen Hinweis gibt.

Ich benutze .inlDateien in zwei Fällen:

  • Zur Definition von Inline-Funktionen.
  • Für Definitionen von Funktionsvorlagen.

In beiden Fällen füge ich die Deklarationen der Funktionen in eine Header-Datei ein, die in anderen Dateien enthalten ist, und dann #includedie .inlDatei am Ende der Header-Datei.

Ich mag es, weil es die Schnittstelle von der Implementierung trennt und die Header-Datei ein wenig leichter lesbar macht. Wenn Sie sich für die Implementierungsdetails interessieren, können Sie die .inlDatei öffnen und lesen. Wenn Sie dies nicht tun, müssen Sie es nicht tun.

Nick Meyer
quelle
2
In der Tat geht es hauptsächlich darum, die Schnittstelle von der Implementierung zu trennen.
Pavel Minaev
1
Ich habe auch .ipp und .ixx für Inline-Definitionen und .tpp und .txx für die erste Vorlage gesehen.
AProgrammer
1
Beispielsweise wird die GNU Standard C ++ Library .tccfür Vorlagenimplementierungsdateien verwendet.
Musiphil
1
@NickMeyer glmverwendet .hpp und .inl genauso wie oben erwähnt. Gut zu wissen, danke für die tolle Antwort :)
legends2k
Also ist es wie ein Header?
Aaron Franke
90

Nick Meyer hat recht: Der Compiler kümmert sich nicht um die Erweiterung der Datei, die Sie einschließen, also Dinge wie ".h", ".hpp", ".hxx", ".hh", ".inl", ".inc" usw. sind eine einfache Konvention, um zu verdeutlichen, was die Dateien enthalten sollen.

Das beste Beispiel sind die STL-Header-Dateien, die keinerlei Erweiterung haben.

Normalerweise enthalten ".inl" -Dateien Inline- Code (daher die Erweiterung ".inl").

Diese ".inl" -Dateien sind eine Notwendigkeit, wenn Sie einen Abhängigkeitszyklus zwischen dem Header- Code haben.

Beispielsweise:

// A.hpp
struct A
{
    void doSomethingElse()
    {
       // Etc.
    }

    void doSomething(B & b)
    {
       b.doSomethingElse() ;
    }
} ;

Und:

// B.hpp
struct B
{
    void doSomethingElse()
    {
       // Etc.
    }

    void doSomething(A & a)
    {
       a.doSomethingElse() ;
    }
} ;

Es gibt keine Möglichkeit, es kompilieren zu lassen, einschließlich der Verwendung der Vorwärtsdeklaration.

Die Lösung besteht dann darin, Definition und Implementierung in zwei Arten von Header-Dateien aufzuteilen:

  • hpp für die Headerdeklaration / -definition
  • inl für die Header-Implementierung

Was sich in folgendes Beispiel aufteilt:

// A.hpp

struct B ;

struct A
{
    void doSomethingElse() ;
    void doSomething(B & b) ;
} ;

Und:

// A.inl
#include <A.hpp>
#include <B.hpp>

inline void A::doSomethingElse()
{
   // Etc.
}

inline void A::doSomething(B & b)
{
   b.doSomethingElse() ;
}

Und:

// B.hpp

struct A ;

struct B
{
    void doSomethingElse() ;
    void doSomething(A & a) ;
} ;

Und:

// B.INL
#include <B.hpp>
#include <A.hpp>

inline void B::doSomethingElse()
{
   // Etc.
}

inline void B::doSomething(A & a)
{
   a.doSomethingElse() ;
}

Auf diese Weise können Sie jede benötigte ".inl" -Datei in Ihre eigene Quelle aufnehmen, und es funktioniert.

Auch hier sind die Suffixnamen der enthaltenen Dateien nicht wirklich wichtig, sondern nur ihre Verwendung.

paercebal
quelle
5
Dies erklärt den wirklichen Nutzen (oder die Notwendigkeit) der Trennung und hätte als Antwort gewählt werden sollen.
Musiphil
Wenn die Funktion nicht inline wäre, würden Sie eine Standard-CPP-Datei für den Implementierungsteil verwenden?
Bublafus
@Bublafus :: If the function were not inline, you would you standard .cpp file for the implementation part?Möglicherweise. Vorlagen sind Beispiele für Code, der normalerweise nicht in CPP-Dateien ausgeblendet werden kann. In diesem Fall ist die INL-Datei obligatorisch.
Paercebal
32

Da hat es sonst niemand erwähnt:

Die Verwendung von INL-Dateien zum Speichern Ihrer Inline-Funktionen kann hilfreich sein, um das Kompilieren zu beschleunigen.

Wenn Sie nur die Deklarationen (.h) einschließen, in denen Sie Deklarationen benötigen, und nur Inline-Implementierungen (.inl) einschließen, in denen Sie sie benötigen (dh wahrscheinlich nur in .cpp- und anderen .inl-Dateien, nicht in .hs), kann a positive Auswirkung auf Ihre Header-Abhängigkeiten.

Dies kann bei größeren Projekten mit vielen interagierenden Klassen ein bedeutender Gewinn sein.

Andy J Buchanan
quelle
7
+1: Die Welt ist definitiv ein anderer Ort, wenn Sie Millionen von Codezeilen und Tausende von Dateien verwalten.
Gatorfax
Sie sollten also niemals .inl in Header-Dateien aufnehmen? Ich hatte immer das Gefühl, dass .inl am Ende von Header-Dateien stehen sollte, da Inline-Funktionen eine Deklaration und Implementierung erfordern, um gleichzeitig erreichbar zu sein.
Icebone1000
1
Icebone1000 Nicht alle Module, die den Header enthalten, möchten unbedingt die Inline-Funktionen verwenden, sodass die Implementierungen nicht eingelesen werden müssen. Sie müssen nicht vorhanden sein, wenn sie nicht verwendet werden.
Andy J Buchanan
1
Ich verstehe nicht, wie es schneller sein kann, da der Compiler mehr Arbeit leisten muss, um die Übersetzungseinheiten einzuschließen und zu kombinieren.
Nikos
1
@Nikos Ich denke, er meinte schneller als das Einfügen all Ihrer Inline-Funktionen in Ihre Header-Dateien.
CoffeeTableEspresso
3

Nach meiner Erfahrung werden INL-Dateien verwendet, um Inline-Funktionen zu definieren. Wenn sie sich in einer INL-Datei befinden, kann die Datei in einem Header enthalten sein, um Inline-Funktionen abzurufen, und in einer C-Datei, um reguläre Funktionsdefinitionen abzurufen.

Auf diese Weise kann dieselbe Quelle einfacher mit Compilern arbeiten, die keine Inline-Funktionsunterstützung haben, als auch mit Compilern, die dies tun.

Sie werden normalerweise mit reinem C-Code verwendet, nicht oft mit C ++ - Code, da alle C ++ - Compiler Inline-Funktionen unterstützen.

Michael Burr
quelle
Ich sehe keinen Sinn darin, dies nur zu tun, um C-Unterstützung zu erhalten. Für C würden Sie nur bedingt #define inline staticIhre Inline-Funktionen in der Kopfzeile definieren.
Pavel Minaev
Ich denke, dies verhindert, dass mehrere Kopien derselben Funktion in der Binärdatei landen. Ich sage nur, dass ich gesehen habe, wie INL-Dateien auf diese Weise verwendet wurden, nicht dass dies die einzige (oder sogar die beste) Technik ist.
Michael Burr
1

Ich glaube, es ist nur eine Namenskonvention für eine "Header" -Datei, die Inline-Code enthält. Es ist so, dass .h-Dateien Definitionen enthalten können und .inl-Dateien Inline-Code enthalten, der für Vorlagen erforderlich ist.

Ich glaube nicht, dass es mehr als eine Namenskonvention gibt, um den Zweck der Datei klar zu machen

jcoder
quelle