Significato di un file .inl in C ++


108

Quali sono i vantaggi di avere dichiarazioni in un file .inl? Quando dovrei usare lo stesso?


3
FWIW, odio i file .inl. Perché suddividere il codice più del necessario?
Shog9

10
@ shog9: separare l'interfaccia dall'implementazione. Ho sempre odiato C # e il file Java perché è così difficile leggere l'interfaccia a causa di tutti i dettagli di implementazione di messey.
Martin York

8
@Martin - sfortunatamente il C ++ ci offre una pessima combinazione di entrambi i mondi: l'interfaccia e parte dell'implementazione nell'intestazione, il resto dell'implementazione nel file .cpp. Anche se eviti le funzioni inline (o le inserisci in file .inl) devi ingombrare l'interfaccia con i fastidiosi dettagli dei membri privati ​​a meno che tu non sia in grado di usare religiosamente l'idioma pimpl.
Michael Burr

5
Sì, non ho mai capito l'argomento secondo cui le intestazioni separano l'interfaccia dall'implementazione. Ovviamente no. Un'interfaccia non dovrebbe contenere tutti i membri privati.
jalf

@LokiAstari: Ad essere onesti, Java / C # ha strumenti molto buoni che forniscono automaticamente lo schema dell'interfaccia. Si potrebbe metterla al contrario: in C ++ devi risolvere manualmente un problema, che può essere completamente risolto dai computer.
bluenote10

Risposte:


139

.inli file non sono mai obbligatori e non hanno alcun significato speciale per il compilatore. È solo un modo per strutturare il codice che fornisce un suggerimento agli umani che potrebbero leggerlo.

Uso i .inlfile in due casi:

  • Per le definizioni delle funzioni inline.
  • Per le definizioni dei modelli di funzione.

In entrambi i casi, metto le dichiarazioni delle funzioni in un file di intestazione, che è incluso da altri file, quindi ho #includeil .inlfile in fondo al file di intestazione.

Mi piace perché separa l'interfaccia dall'implementazione e rende il file di intestazione un po 'più facile da leggere. Se ti interessano i dettagli di implementazione, puoi aprire il .inlfile e leggerlo. Se non lo fai, non devi.


2
In effetti, si tratta principalmente di separare l'interfaccia dall'implementazione.
Pavel Minaev

1
Ho anche visto .ipp e .ixx usati per le definizioni inline e .tpp e .txx per il modello uno.
APProgrammatore

1
Ad esempio, la libreria GNU Standard C ++ utilizza .tccper i file di implementazione dei modelli.
musiphil

1
@ NickMeyer glmusa .hpp e .inl esattamente nello stesso modo che hai menzionato sopra. Buono a sapersi, grazie per l'ottima risposta :)
legends2k

Quindi è come un'intestazione?
Aaron Franke

90

Nick Meyer ha ragione: al compilatore non interessa l'estensione del file che stai includendo, quindi cose come ".h", ".hpp", ".hxx", ".hh", ".inl", ".inc", ecc. sono una semplice convenzione, per chiarire cosa dovrebbero contenere i file.

Il miglior esempio sono i file di intestazione STL che non hanno alcuna estensione.

Di solito, i file ".inl" contengono codice inline (da cui l'estensione ".inl").

Quei file ".inl" sono una necessità quando si ha un ciclo di dipendenza tra il codice dell'intestazione .

Per esempio:

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

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

E:

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

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

Non c'è modo di compilarlo, incluso l'uso della dichiarazione in avanti.

La soluzione è quindi suddividere la definizione e l'implementazione in due tipi di file di intestazione:

  • hpp per la dichiarazione / definizione dell'intestazione
  • inl per l'implementazione dell'intestazione

Che si scompone nel seguente esempio:

// A.hpp

struct B ;

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

E:

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

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

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

E:

// B.hpp

struct A ;

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

E:

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

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

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

In questo modo, puoi includere qualsiasi file ".inl" di cui hai bisogno nel tuo codice sorgente e funzionerà.

Ancora una volta, i nomi dei suffissi dei file inclusi non sono molto importanti, solo il loro utilizzo.


5
Questo spiega il vero vantaggio (o necessità) della separazione e avrebbe dovuto essere scelto come risposta.
musiphil

Se la funzione non fosse in linea, useresti un file .cpp standard per la parte di implementazione?
Bublafus

@Bublafus If the function were not inline, you would you standard .cpp file for the implementation part?:: Forse. I modelli sono esempi di codice che in genere non possono essere nascosti nei file .CPP, quindi in tal caso il file .INL sarebbe obbligatorio.
paercebal

32

Poiché nessun altro lo ha menzionato:

L'uso di file .inl per memorizzare le funzioni inline può essere utile per velocizzare le compilazioni.

Se includi solo le dichiarazioni (.h) in cui hai bisogno di dichiarazioni e includi solo implementazioni inline (.inl) dove ne hai bisogno (cioè probabilmente solo in .cpp e altri file .inl, non .h), può avere un effetto benefico sulle dipendenze dell'intestazione.

Questa può essere una vittoria significativa su progetti più grandi con molte classi interagenti.


7
+1: il mondo è decisamente un posto diverso quando gestisci milioni di righe di codice e migliaia di file.
gatorfax

quindi non dovresti mai includere .inl nei file di intestazione? Ho sempre avuto la sensazione che .inl dovesse essere messo in fondo ai file di intestazione poiché le funzioni inline richiedono dichiarazione e implementazione per essere raggiungibili contemporaneamente.
Icebone1000

1
Icebone1000 non tutti i moduli che includono l'intestazione vogliono necessariamente usare le funzioni inline, quindi non hanno bisogno di leggere le implementazioni, non devono essere presenti se non vengono utilizzate.
Andy J Buchanan

1
Non capisco come possa essere più veloce, dal momento che il compilatore deve fare più lavoro per includere e combinare le unità di traduzione.
Nikos

1
@ Nikos Penso che intendesse più veloce rispetto all'inserimento di tutte le funzioni inline nei file di intestazione.
CoffeeTableEspresso

3

Nella mia esperienza, i file .inl vengono utilizzati per definire le funzioni inline. Quando si trovano in un file .inl, il file può essere incluso in un'intestazione per ottenere funzioni inline e in un file .c per ottenere definizioni di funzioni regolari.

In questo modo la stessa sorgente può lavorare più facilmente con i compilatori che non hanno il supporto per le funzioni inline così come i compilatori che lo hanno.

Di solito vengono utilizzati con codice C semplice, non spesso con codice C ++ poiché tutti i compilatori C ++ supportano le funzioni inline.


Non vedo il punto nel farlo solo per ottenere il supporto C. Per C, dovresti solo condizionatamente #define inline statice definire le tue funzioni inline nell'intestazione.
Pavel Minaev

Immagino che questo eviti che più copie della stessa funzione finiscano nel binario. Sto solo dicendo che ho visto i file .inl usati in questo modo, non che sia l'unica tecnica (o anche la migliore).
Michael Burr

1

Credo che sia solo una convenzione di denominazione per un file di "intestazione" che include codice in linea. è così che i file .h possono contenere definizioni e i file .inl contengono codice inline necessario per i modelli.

Non credo ci sia altro che una convenzione di denominazione per rendere chiaro lo scopo del file

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.