inline specifier
Спецификатор inline, используемый в decl-specifier-seq функции, объявляет функцию inline-функцией.
Функция, полностью определённая внутри определения class/struct/union, будь то функция-член или функция friend, не являющаяся членом класса, неявно является inline-функцией, если только она не принадлежит именованному модулю(начиная с C++20).
| Функция, объявленная как constexpr или consteval(начиная с C++20) в своём первом объявлении, неявно является inline-функцией. Удалённая функция неявно является inline-функцией: её (удалённое) определение может присутствовать более чем в одной единице трансляции. | (начиная с C++11) |
| Спецификатор inline, используемый в decl-specifier-seq переменной со статической длительностью хранения (статического члена класса или переменной в пространстве имён), объявляет переменную inline-переменной. Статический член-данных, объявленный как constexpr в своём первом объявлении, неявно является inline-переменной. | (начиная с C++17) |
Пояснение
Inline-функция или inline-переменная(начиная с C++17) обладает следующими свойствами:
- Определение inline-функции или переменной(начиная с C++17) должно быть доступно в единице трансляции, в которой к ней обращаются (не обязательно до точки обращения).
- Inline-функция или переменная(начиная с C++17) с внешним связыванием (например, не объявленная как static) обладает следующими дополнительными свойствами:
- В программе может быть несколько определений inline-функции или переменной(начиная с C++17), если каждое определение находится в отдельной единице трансляции и (для нестатических inline-функций и переменных(начиная с C++17)) все определения идентичны. Например, inline-функция или inline-переменная(начиная с C++17) может быть определена в заголовочном файле, включённом в несколько исходных файлов.
- Она должна быть объявлена как inline в каждой единице трансляции.
- Она имеет один и тот же адрес во всех единицах трансляции.
В inline-функции:
- Локальные статические объекты функции во всех определениях функции являются общими для всех единиц трансляции (все они ссылаются на один и тот же объект, определённый в одной единице трансляции).
- Типы, определённые во всех определениях функции, также одинаковы во всех единицах трансляции.
| Inline-константные переменные в пространстве имён по умолчанию имеют внешнее связывание (в отличие от неквалифицированных как volatile константных переменных, не являющихся inline). | (начиная с C++17) |
Изначально ключевое слово inline предназначалось для того, чтобы указывать оптимизатору на предпочтительность встраивания функции вместо вызова функции, то есть вместо выполнения инструкции процессора, передающей управление телу функции при вызове, выполняется копия тела функции без генерации вызова. Это позволяет избежать накладных расходов, связанных с вызовом функции (передачей аргументов и получением результата), но может привести к увеличению размера исполняемого файла, поскольку код функции приходится повторять несколько раз.
Поскольку встраивание функции ненаблюдаемо в рамках стандартной семантики, компиляторы могут использовать встраивание для любой функции, не помеченной как inline, и могут генерировать вызовы для любой функции, помеченной как inline. Эти варианты оптимизации не меняют приведённые выше правила, касающиеся нескольких определений и общих статических объектов.
| Поскольку начиная с C++98 значение ключевого слова inline применительно к функциям стало означать «разрешено несколько определений», а не «предпочтительно встраивание», это значение было распространено и на переменные. | (начиная с C++17) |
Примечания
Если inline-функция или переменная(начиная с C++17) с внешним связыванием определена по-разному в разных единицах трансляции, программа некорректна; диагностика не требуется.
Спецификатор inline нельзя использовать в объявлении функции или переменной(начиная с C++17) на уровне блока (внутри другой функции).
Спецификатор inline нельзя использовать для повторного объявления функции или переменной(начиная с C++17), уже определённой в единице трансляции как не-inline.
Неявно генерируемые функции-члены и любые функции-члены, объявленные как defaulted в своём первом объявлении, являются inline, как и любые другие функции, определённые внутри определения класса.
Если inline-функция объявлена в разных единицах трансляции, совокупные наборы аргументов по умолчанию должны быть одинаковыми в конце каждой единицы трансляции.
В C inline-функции не требуется объявлять как inline в каждой единице трансляции (не более одной из них может быть не-inline или externinline); определения функций не обязаны быть идентичными (но поведение программы не определено, если оно зависит от того, какое из них вызывается), а локальные статические объекты функции в разных определениях одной и той же функции являются разными.
| Дополнительные правила для inline-статических членов см. в разделе статические члены-данных. Inline-переменные устраняют главное препятствие для распространения кода C++ в виде библиотек, состоящих только из заголовочных файлов. | (начиная с C++17) |
| Макрос проверки поддержки функции | Значение | Стандарт | Функция |
|---|---|---|---|
__cpp_inline_variables | 201606L | (C++17) | Inline-переменные |
Ключевые слова
Пример
Заголовочный файл "example.h":
#ifndef EXAMPLE_H
#define EXAMPLE_H
#include <atomic>
// function included in multiple source files must be inline
inline int sum(int a, int b)
{
return a + b;
}
// variable with external linkage included in multiple source files must be inline
inline std::atomic<int> counter(0);
#endif
Исходный файл #1:
#include "example.h"
int a()
{
++counter;
return sum(1, 2);
}
Исходный файл #2:
#include "example.h"
int b()
{
++counter;
return sum(3, 4);
}
Отчёты об ошибках стандарта
Следующие отчёты об ошибках, изменяющие поведение, были применены задним числом к ранее опубликованным стандартам C++.
| DR | Применён к | Опубликованное поведение | Правильное поведение |
|---|---|---|---|
| CWG 281 | C++98 | объявление функции friend могло использовать спецификатор inline, даже если функция, для которой объявлена дружба, не является inline-функцией | запретить такое использование |
| CWG 317 | C++98 | функцию можно было объявить inline, даже если до этого объявления в той же единице трансляции имелось её не-inline-определение | в этом случае программа некорректна |
| CWG 765 | C++98 | тип, определённый в inline-функции, мог различаться в разных единицах трансляции | такие типы одинаковы во всех единицах трансляции |
| CWG 1823 | C++98 | строковые литералы во всех определениях inline-функции были общими для всех единиц трансляции | это требование удалено ради согласованности и поддержки реализаций |
| CWG 2531 | C++17 | статический член-данных мог неявно быть inline, даже если в его первом объявлении он не был объявлен как constexpr | в этом случае он не является неявно inline |
См. также
Документация по C о inline |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/inline