Значення файлу .inl у C ++


108

Які переваги мають декларації у файлі .inl? Коли мені потрібно використовувати те саме?


3
FWIW, я ненавиджу .inl файли. Навіщо розділяти свій код більше, ніж потрібно?
Shog9

10
@ shog9: для використання інтерфейсу від реалізації. Я завжди ненавидів файл C # та Java, тому що його так важко читати інтерфейс через усі деталі реалізації messey.
Мартін Йорк

8
@Martin - на жаль, C ++ дає нам погану комбінацію обох світів - інтерфейсу та частини реалізації у заголовку, решту реалізації у файлі .cpp. Навіть якщо ви уникаєте вбудованих функцій (або поміщаєте їх у .inl-файли), вам доведеться захаращувати інтерфейс з прикрістю деталей приватних членів, якщо ви не можете релігійно використовувати ідіому pimpl.
Майкл Берр

5
Так, я ніколи не розумів аргумент того, що заголовки відокремлюють інтерфейс від реалізації. Вони, очевидно, ні. Інтерфейс не повинен містити всіх приватних членів.
jalf

@LokiAstari: Для справедливості, Java / C # має дуже хороший інструментарій, що забезпечує контур інтерфейсу автоматично. Можна сказати і навпаки: у C ++ вам доведеться вручну вирішити проблему, яку можна повністю вирішити комп’ютерами.
bluenote10

Відповіді:


139

.inlфайли ніколи не є обов'язковими і не мають особливого значення для компілятора. Це лише спосіб структурування коду, який надає підказки людям, які можуть його прочитати.

Я використовую .inlфайли у двох випадках:

  • Для визначення вбудованих функцій.
  • Для визначення шаблонів функцій.

В обох випадках я поміщав оголошення функцій в заголовки, який включений іншими файлами, то я #includeна .inlфайл в нижній частині заголовка файлу.

Мені це подобається, оскільки він відділяє інтерфейс від реалізації та робить файл заголовка трохи легшим для читання. Якщо ви дбаєте про деталі реалізації, ви можете відкрити .inlфайл і прочитати його. Якщо ні, то не потрібно.


2
Дійсно, мова йде переважно про відділення інтерфейсу від реалізації.
Павло Мінаєв

1
Я також бачив .ipp і .ixx, які використовуються для вбудованих визначень, а .tpp і .txx для шаблону першого.
AProgrammer

1
Наприклад, стандартна бібліотека C ++ GNU використовується .tccдля файлів реалізації шаблонів.
musiphil

1
@NickMeyer glmвикористовує .hpp та .inl точно так само, як ви згадали вище.
Приємно

Так це як заголовок?
Аарон Франке

90

Нік Мейєр правий: компілятор не переймається розширенням файлу, який ви включаєте, тому такі речі, як ".h", ".hpp", ".hxx", ".hh", ".inl", ".inc" тощо - це звичайна умова, щоб зрозуміти, що файли повинні містити.

Найкращий приклад - файли заголовків STL, які не мають жодного розширення.

Зазвичай файли ".inl" містять вбудований код (звідси розширення ".inl").

Ці файли ".inl" - це необхідність, коли у вас є цикл залежності між кодом заголовка .

Наприклад:

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

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

І:

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

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

У вас немає ніякого способу компілювати його, включаючи використання прямої декларації.

Тоді рішення полягає в розбитті визначення та реалізації на два типи файлів заголовків:

  • hpp для оголошення / визначення заголовка
  • inl для реалізації заголовка

Який розбивається на наступний приклад:

// A.hpp

struct B ;

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

І:

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

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

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

І:

// B.hpp

struct A ;

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

І:

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

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

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

Таким чином, ви можете включити будь-який файл ".inl" у свій власний джерело, і він буде працювати.

Знову ж таки, імена суфіксів включених файлів насправді не важливі, а лише їх використання.


5
Це пояснює реальну користь (або необхідність) розлуки, і її слід було обрати як відповідь.
musiphil

Якби функція не була вбудованою, ви б застосували стандарт .cpp-файл для частини реалізації?
Бублафус

@Bublafus If the function were not inline, you would you standard .cpp file for the implementation part?:: Можливо. Шаблони - це приклади коду, які зазвичай не можна приховати у файлах .CPP, тому в цьому випадку .INL-файл буде обов'язковим.
paercebal

32

Оскільки ніхто інший цього не згадував:

Використання файлів .inl для зберігання вбудованих функцій може бути корисним для прискорення компіляції.

Якщо ви включаєте лише декларації (.h) там, де вам потрібні декларації, і включаєте лише вбудовані реалізації (.inl) там, де вони вам потрібні (тобто, ймовірно, лише у .cpp та інші .inl файли, а не .h's), вони можуть мати сприятливо впливає на залежність вашого заголовка.

Це може бути значним виграшем у великих проектах із багатьма взаємодіючими класами.


7
+1: світ, безумовно, інше місце, коли ви керуєте мільйонами рядків коду та тисячами файлів.
gatorfax

тож ніколи не слід включати .inl у файли заголовків? У мене завжди було відчуття, що .inl слід розміщувати внизу файлів заголовків, оскільки вбудовані функції вимагають одразу оголошення та реалізації.
Icebone1000

1
Icebone1000 не всі модулі, що містять заголовок, обов'язково хочуть використовувати вбудовані функції, тому у них немає необхідності в читанні реалізації, вони не повинні бути присутніми, якщо вони не використовуються.
Andy J Buchanan

1
Я не розумію, як це може бути швидше, оскільки компілятору доводиться робити більше роботи, щоб включити та об'єднати блоки перекладу.
Нікос

1
@Nikos Я думаю, що він мав на увазі швидше відносно введення всіх своїх вбудованих функцій у файли заголовків.
CoffeeTableEspresso

3

На мій досвід, .inl файли використовуються для визначення вбудованих функцій. Коли вони знаходяться у файлі .inl, файл можна включити до заголовка для отримання вбудованих функцій, а у .c-файл для отримання регулярних визначень функцій.

Таким чином, те саме джерело може легше працювати з компіляторами, які не мають вбудованих функцій підтримки, а також компіляторами, які це роблять.

Зазвичай вони використовуються з прямим кодом C, а не часто з кодом C ++, оскільки всі компілятори C ++ підтримують вбудовані функції.


Я не бачу сенсу робити це лише для того, щоб отримати підтримку C. Для C, ви просто умовно #define inline staticі визначите свої вбудовані функції у заголовку.
Павло Мінаєв

Я думаю, що це дозволяє уникнути того, щоб кілька копій однієї і тієї ж функції не закінчувались бінарними. Я просто кажу, що я бачив .inl файли, які використовуються таким чином, не те, що це єдина техніка (або навіть найкраща).
Майкл Берр

1

Я вважаю, що це лише умова іменування для файлу "заголовка", що включає вбудований код. це так, що .h файли можуть містити визначення, а .inl файли містять вбудований код, необхідний для шаблонів.

Я не вірю, що в ньому є щось більше, ніж угода про іменування, щоб зрозуміти мету файлу

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.