Уже в С++98 у нас были const, volatile, static, extern, inline и, конечно, шаблоны. В С++11 добавились thread_local, constexpr, а также extern для шаблонов. В С++14 добавились шаблоны переменных. В С++17 — inline переменные. В С++20 обещают подвезти consteval и constinit. А вы когда-нибудь задумывались, что такое template static inline thread_local constexpr const volatile переменная?
В этом докладе Михаил попытается разложить по полочкам всё это многообразие ключевых слов. Вспомним про linkage, storage duration и инстанциации шаблонов (и что изменится с приходом модулей в С++20). Разберёмся, какая связь между template и inline, между static и constexpr. Поймём, зачем нам extern, когда у нас есть inline. И осознаем, как нам потребовалось почти 20 лет, чтобы научиться нормально объявлять константы.
Table of Contents:
- Сборка С/С++ программ
- Что такое объявление и определение
- Linkage
- Storage Duration
- Волшебный static
- Const-qualified variables
- Inline переменные
- Constexpr функции
- No diagnostic required
- Комбинации storage duration и linkage
- Алгоритм как определять storage duration
- Extern
- На примерах
- Шаблоны
- Inline functions templates
- Объявление явной инстанции шаблона
- Константы
- C++20
- Рекомендации
Сборка С/С++ программ
Единицы трансляции (translation unit) - сущность формируемая precrocessor, компилируя их мы получаем объектные файлы.
Что такое объявление и определение
Linkage
Второй пример (a’.cpp) не соберется из-за static
, т.к. это изменит линковку функции, и она будет видна только в своей единице трансляции.
Всего в C++ есть 3 вида linkage:
External - доступна во всех единицах трансляции.
Internal - только в текущей трансляции.
No - только в текущей области видимости.
Storage Duration
В первом случаем переменная всегда будет 0, во втором же переменная проинициализируется в первый раз 0 и память под нее будет выделена в начале программы, а далее все время будет “жить” и хранить значение.
Волшебный static
Static
особенное слово, в зависимости от контекста оно может влиять на линковку, а может на storage duration.
Const-qualified variables
Любая переменная объявленная на уровне пространства имет internal linkage
если он cv-qualified
. Но в примере ругается линковщик на то, что name
это указатель на константные данные, но указатель не const
.
Constexpr
влечет за собой const:
Пример работы internal linkage
:
Inline переменные
Inline
работает следующим образом: в каждой единице трансляции на этапе компиляции создается свой объект, но этот символ при попадании в объектник получит отметку weak
, и линковщик потом выберет только один.
Constexpr функции
Однако, если функция constexpr qualified то она становится inline
.
В современном C++
inline
это скорее не про то, что функция будет встраиваться, а про то,что это будет external (weak) linkage
и комплятор позаботиться о том, что это функция будет одна.
No diagnostic required
В C++
представленна ситуация ведет к неопределенном поведению и никак не обрабатывается компилятором. И в каждом компиляторе будет свой вывод.
Такие ситуации слишком сложно диагностировать и принято решение не нагружать компиляторы.
Решение данной проблемы заключается в использовании анонимных namespace
. Ничего из анонимного пространства имен не торчит наружу. И тогда эти структуры и функции будут иметь internal linkage
.
Комбинации storage duration и linkage
Легенда к изображениям:
Алгоритм как определять storage duration
Extern
До появления inline
для получения external linkage
для переменных использовался extern
.
Но у него есть преимущество, если с inline объект помещался бы в каждый объектный файл, то extern
приводит к тому, что мы получаем определение переменной, а инициализируется и создается она единожды.
На примерах
Шаблоны
Не бывает шаблонных сущностей, бывают шаблоны сущностей.
При создании шаблонной сущности происходит неявная инстанциация шаблона.
Если вы хотите убедиться, что у вас действительно один объект, используйте inline
(отличный спобос создания констант)
Inline functions templates
Объявление явной инстанции шаблона
Константы
Вот best practice объявления констант:
Но когда введут модули и у нас не будет h файлов, все эти сложности уйдут:
Алгоритм выбора квалификаторов для констант: