inline constexpr



В прошлом мы уже обсуждали, что удобно определять константы в заголовочнике и помечать их inline constexpr. Я бы сегодня хотел поговорить в целом про два этих ключевых слова и рассмотреть, как они друг на друга влияют.



Как мы знаем, inline - теперь это больше про линковку, а про эту сторону inline мы знаем уже довольно много. Куча постов было про это за последний месяц. Базово inline обеспечивает внешнее связывание и предоставляет компилятору партийный билет на нарушение odr, который дает право иметь по одному определению сущности на одну единицу трансляции, а не на всю программу, как обычные смертные.



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



У нас опять куча вариантов, какие сущности мы можем пометить constexpr. Но в разрезе линковки их всего 2, поэтому будет полегче.



Первая группа - спецификатор используется при определении объектов. В этом случае подразумевается, что эти объекты помечены const. А это уже значит, что они базово имеют внутреннюю линковку. Кстати, константы можно помечать extern, чтобы у них сменился вид линковки с внутренней на внешнюю. А вот constexpr объекты - нельзя. Потому что связка объявления символа с его значением при внешнем связывании происходит на этапе линковки. А constexpr требует, чтобы значение было известно на этапе компиляции.



Вторая группа - функции и статические члены класса. В этом случае подразумевается, что они неявно помечены inline. На это есть весьма веские причины(по-другому и не делается). Функции, которые могут выполнять вычисления в compile-time, должны быть видны на этом самом этапе компиляции всем единицам трансляции. Так что extern мы сразу отбрасываем, такого не может быть. Они могли бы помечаться static, но тогда потенциально будет дублироваться код функции во всех единицах трансляции. А inline решает все проблемы. Функцию видно во всех единицах трансляции, куда она подключается. А код на этапе линковки объединяется в одно определение и никакого дублирования.



Для статических полей класса похожая схема. Раз их определение должно быть видно всем единицам трансляции, которые видят этот класс, то их нужно определять внутри описания класса. А это(за исключением пары случаев) можно сделать только, если пометить статический член как inline.



Получается, что нет смысла писать inline constexpr для любого рода функций(которые в принципе могут быть constexpr) и для статических поле классов. Это можно сделать, чтобы подсветить эту конкретную особенность и намерение(?), но, на самом деле, непонятно, что это изменит.



А вот глобальные объекты есть смысл помечать inline. Чтобы избежать издержек внутренней линковки объектов. Поэтому в примере из прошлого поста именно так и было сделано.



Продолжаем штудировать тему inline и линковки. Если вы устали от этой однотипной тематики, то ставьте реакцию🗿, постараемся разбавить эту духоту. Хочется просто сделать связный рассказ, чтобы вы из контекста не выпадали. Но если это мешает, то поменяем тактику.



Dig to the core. Stay cool.



#cpp11 #cpp17 #cppcore #compiler