Учитывая следующее объявление в глобальном пространстве имен:
constexpr int x = x;
Является ли это хорошо сформированным?
В стандартном разделе проекта С++ 14 3.6.2
[basic.start.init] говорится:
Переменные со статической продолжительностью хранения (3.7.1) или продолжительностью хранения потоков (3.7.2) должны быть инициализированы нулями (8.5) перед любой другой инициализацией. [...]
То, что, по-видимому, хорошо описывает пример, заключается в том, что x
инициализируется собственным значением при постоянной инициализации, которая будет 0
из-за нулевой инициализации.
Это действительно так? clang принимает этот код, а gcc производит диагностику:
error: the value of 'x' is not usable in a constant expression
constexpr int x = x;
^
Ответ 1
Это было выяснено и плохо сформировано отчет о дефекте 2026: Нулевая инициализация и constexpr, в котором говорится:
Согласно пункту 3.6.2 [basic.start.init],
Переменные со статической продолжительностью хранения (3.7.1 [basic.stc.static]) или длительность хранения потоков (3.7.2 [basic.stc.thread]) должна быть нулевой инициализации (8.5 [dcl.init]) перед любой другой инициализацией происходит.
Это относится и к постоянной инициализации? Например, должно быть хорошо сформировано, опираясь на предполагаемую нулевая инициализация, предшествующая постоянной инициализации?
constexpr int i = i;
struct s {
constexpr s() : v(v) { }
int v;
};
constexpr s s1;
В записке перед предлагаемой резолюцией говорится:
CWG согласилась с тем, что постоянную инициализацию следует рассматривать как происходящую вместо нулевой инициализации в этих случаях, делая объявления плохо сформированными.
и предлагаемая резолюция уточняет и среди многих изменений удаляет следующую формулировку:
Переменные со статической продолжительностью хранения (3.7.1) или продолжительностью хранения потоков (3.7.2) должны быть инициализированы нулями (8.5) перед любой другой инициализацией. [...]
и добавляет следующую формулировку:
Если постоянная инициализация не выполняется, переменная со статической продолжительностью хранения (3.7.1 [basic.stc.static]) или длительность хранения потока (3.7.2 [basic.stc.thread]) инициализируется нулем (8.5 [dcl.init]). [...]
Это большое изменение, оно переименовывает [basic.start.init] в [basic.start.static] и создало новый раздел [basic.start.dynamic] и модифицирует [stmt.dcl]