Ответ 1
Примечание. Начиная с С++ 17 вы можете объявить переменные как встроенные.
TL; DR. Если вы хотите быть на (очень) безопасной стороне, перейдите к функциям constexpr. Это не является неотъемлемо необходимым, хотя, конечно, не будет, если вы выполняете тривиальные операции над этими объектами и интересуетесь исключительно их значением или просто не используете их в опасных сценариях, перечисленных ниже.
Основная проблема заключается в том, что переменные const
в области пространства имен, такие как ваши (обычно), имеют внутреннюю привязку ([basic.link]/(3.2)). Это означает, что каждая единица перевода, компилирующая соответствующий заголовок, будет наблюдать другой объект (т.е. Символ).
Теперь представьте, что у нас есть шаблон или встроенная функция в заголовке с использованием этих объектов. ODR очень точно описывает этот сценарий - [basic.def.odr]/6:
", инициализированное постоянным выражением", безусловно, встречается, так как мы говорим constexpr
. Таким образом, "объект имеет то же значение во всех определениях D
", если вы не обезьяны.
"объект не используется odr", вероятно, является единственным сомнительным условием. В принципе, это требует, чтобы вы не требовали существования среды исполнения в качестве символа, что, в свою очередь, подразумевает, что
-
Вы не привязываете его к ссылке (= > вы ее не пересылаете!)
-
Вы не выполняете (не прямо или неявно) свой адрес.
Единственное исключение из второго правила - это массивы, которые могут быть взяты неявным образом внутри операции индекса, если два вышеприведенных правила не нарушены для полученного значения gl.
Точнее, odr-use определяется [basic.def.odr]/3:
Переменная
x
, имя которой отображается как потенциально оцениваемое выражениеex
, является odr-используемымex
, если не применяется преобразование lvalue-to-rvalue (4.1) вx
дает константное выражение (5.20), которое не вызывает никаких нетривиальных функций и, еслиx
является объектом,ex
является элементом множества потенциальные результаты выраженияe
, где либо lvalue-to-rvalue conversion (4.1) применяется кe
, либоe
является выражением отбрасываемого значения (пункт 5).
Применение l-t-r к любой переменной constexpr
будет вести себя так, как требуется первой части. Вторая часть требует, чтобы переменная использовалась как значение, а не фактический объект; то есть он в конечном итоге либо отбрасывается, либо оценивается напрямую, что дает вышеописанные эмпирические правила.
Если вы избегаете использования переменной odr внутри встроенных функций, шаблонов и т.п., вы в порядке. Но если вы используете возвращаемое значение соответствующей функции constexpr, вам не придется беспокоиться, так как prvalues уже ведут себя как значения/литералы (а не объекты), а функции constexpr являются встроенными и определенно не будут нарушать ODR (если вы не используете там переменные constexpr
!).