Хотя в C++ всегда можно было объявить отдельные функции встроенными, C++17 дополнительно позволяет нам объявлять переменные встроенными. Это значительно упрощает реализацию библиотек только для заголовков, что раньше было возможно только с помощью обходных путей.

Давайте создадим пример класса, который может подойти в качестве члена типичной библиотеки только для заголовков. Цель состоит в том, чтобы дать ему статический член и создать его экземпляр глобально доступным способом с помощью ключевого слова inline, что было невозможно до C++17:

Программы C++ часто состоят из нескольких исходных файлов C++ (достаточно .cpp или .cc). Они индивидуально скомпилированы в модули (т. е. объектные файлы обычно имеют .o). Связывание всех модулей вместе в один исполняемый файл или разделяемую/статическую библиотеку является последним шагом.

На этапе компоновки считается ошибкой, если компоновщик может найти определение одного конкретного символа несколько раз. Предположим, например, что у нас есть функция с такой сигнатурой, как int foo();. Если два модуля определяют одну и ту же функцию, какой из них правильный? Компоновщик не может просто бросить кости. Ну, может, но, скорее всего, это не то, чего хотел бы любой программист.

Традиционный способ предоставления глобально доступных функций — объявить их в файлах заголовков, которые будут включены любым модулем C++, которому необходимо их вызвать. Определение каждой из этих функций будет помещено один раз в отдельные файлы модулей. Затем они связываются вместе с модулями, которые хотят использовать эти функции. Эта система соответствует правилу единого определения (ODR).

Однако, если бы это был единственный способ, то было бы невозможно предоставить библиотеки только для заголовков. Библиотеки только для заголовков очень удобны, потому что их нужно только включить с помощью #include в любой программный файл C++, после чего они сразу же становятся доступными. Чтобы использовать библиотеки, которые не предназначены только для заголовков, программист должен также адаптировать сценарии сборки, чтобы компоновщик связывал модули библиотеки вместе со своими собственными файлами модулей. Особенно для библиотек с очень короткими функциями это излишне неудобно.

В таких случаях можно использовать ключевое слово inline, чтобы сделать исключение, чтобы разрешить несколько определений одного и того же символа в разных модулях. Если компоновщик находит несколько символов с одинаковой сигнатурой, но они объявлены встроенными, он просто выберет первый и будет полагать, что остальные символы имеют такое же определение. То, что все одинаковые встроенные символы определяются как полностью равные, в основном является обещанием от программиста.