Ответ 1
Разве постоянная оценка - это не весело?
В языке есть несколько мест, где мы пытаемся выполнять постоянную оценку, и если это не удается, мы возвращаемся к выполнению постоянной оценки non-. Статическая инициализация - одно из таких мест, инициализация константных целых чисел - другое.
Что происходит с:
int const i = f();
это то, что это может быть постоянная оценка, но это не обязательно должно быть. Поскольку (non- constexpr
) постоянные целые числа все еще можно использовать в качестве константных выражений, если они удовлетворяют всем другим условиям, мы должны попытаться. Например:
const int n = 42; // const, not constexpr
std::array<int, n> arr; // n is a constant expression, this is ok
Итак, попробуем сделать - мы называем f()
постоянным выражением. В этом контексте std::is_constant_evaluated()
- это true
, поэтому мы попадаем на ветку с помощью throw
и в итоге терпим неудачу. Невозможно throw
во время постоянной оценки, поэтому наша постоянная оценка не удалась.
Но затем мы отступаем и пытаемся снова - на этот раз мы называем f()
константным выражением non- (то есть std::is_constant_evaluated()
- это false
). Этот путь завершается успешно, давая нам 1
, поэтому i
инициализируется значением 1
. Но примечательно, что i
не является постоянным выражением в этой точке. Последующий static_assert(i == 1)
будет неправильно сформирован, потому что инициализатор i
не является константным выражением! Даже если путь инициализации константы non- (в противном случае) полностью удовлетворяет требованиям константного выражения.
Обратите внимание: если мы попробуем:
constexpr int i = f();
Это не удалось бы, потому что мы не можем вернуться к константе инициализации non-.