Подтвердить что ты не робот

Почему это использование другой константы, определенной позже, квалифицирует выражение как не постоянное выражение

Учитывая пример с этой страницы, воспроизводится ниже

struct S {
    static const int c;
};
const int d = 10 * S::c; // not a constant expression: S::c has no preceding
                         // initializer, this initialization happens after const
const int S::c = 5;      // constant initialization, guaranteed to happen first

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

Если это связано с тем фактом, что постоянная инициализация должна оцениваться во время компиляции, то в стандарте упоминается, что постоянная инициализация не должна выполняться во время компиляции и даже может произойти, например, при загрузке. Тогда почему бы просто не инициализировать c во время компиляции и просто d во время загрузки? (Я мог бы подумать о себе в круг)


Благодаря Jayesh я смог найти аналогичный вопрос "удивительный" постоянная инициализация из-за порядка определения, но ответ, похоже, говорит о преобразовании lvalue в rvalue, где здесь lvalue для преобразования rvalue? Помимо этого не было никакой цитаты из стандарта, о котором здесь было нарушено условие. Ответы также не объясняют, почему инициализация не разделяется на время загрузки и во время компиляции.

4b9b3361

Ответ 1

В соответствии со стандартом §6.6.2/p2 Статическая инициализация [basic.start.static]:

Инициализация констант выполняется, если переменный или временный объект с статикой или длительностью хранения потоков инициализируется константой инициализатор для объекта.

Теперь, в момент инициализации d, компилятор видит, что c еще не статически инициализирован (т.е. еще не определен). Поэтому инициализатор d не квалифицируется как константное выражение, и, следовательно, инициализация d квалифицируется как динамическая инициализация. Поскольку статическая инициализация происходит перед динамической инициализацией, c будет инициализирована до d и, следовательно, во время d. инициализация c уже инициализирована, поэтому код считается действительным.

Теперь, если вы измените порядок инициализации или инициализируете c inline, инициализатор d квалифицируется как константное выражение, потому что компилятор в момент инициализации d уже видел статическую инициализацию c (т.е. определение c).

Теперь ответ о том, почему в первом случае инициализатор d не является константным выражением, приведен в § 8.20/p2. Константные выражения [expr.const] (выделено мной):

2 Выражение e является выражением константы ядра, оценка e, следуя правилам абстрактной машины (4.6), будет оценивать одно из следующих выражений:

...

2.7 - преобразование lvalue-to-rvalue (7.1), если оно не применяется к

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

В выражении 10 * c, c не имеет предшествующей инициализации, поэтому не является постоянным выражением.