[Обратите внимание, что в этом посте a<T>
и b<T>
сокращены до a
и b
соответственно.]
[expr.const/3]
утверждает, что:
Переменная может использоваться в константных выражениях после того, как встречается ее инициализирующее объявление, если это переменная constexpr, или она имеет ссылочный тип или const-квалифицированный целочисленный тип или тип перечисления, а его инициализатор является инициализатором констант.
Таким образом, a
будет использоваться во время инициализации b
из-за спецификатора constexpr
.constexpr
полностью применимо как к переменным, так и к шаблонам переменных, как указано в первом предложении [dcl.constexpr/1]
.
Спецификатор constexpr
должен применяться только копределение переменной или шаблона переменной или объявление функции или шаблона функции.
Таким образом, переменная или шаблон переменной, объявленный constexpr
, может использоваться в константных выражениях (включая инициализацию других * 1035)* переменные) после его собственной инициализации со значением, указанным в его инициализации (из-за постоянной инициализации, косвенно гарантируемой constexpr
).
Если мы хотим исследовать второй вариант в [expr.const/3]
вместо того, чтобы полагаться на условие «constexpr
означает« да »», это также приведет к тому, что a
будет использоваться во время инициализации b
, хотя и по более сложному маршруту, который включает в себя углубление во многие части стандарта и разбиение на части.вместе неявные гарантии.
Во-первых, возник бы вопрос о том,a
имеет постоянный инициализатор .Чтобы определить, имеет ли он постоянный инициализатор, мы можем обратиться к [expr.const/2]
, который гласит (примечание пропущено):
A константа инициализатора для переменнойили временный объект o является инициализатором, для которого интерпретация его полного выражения как константа-выражения приводит к константному выражению, за исключением того, что если o является объектом, такой инициализатор может также вызывать конструкторы constexpr для o иего подобъекты, даже если эти объекты имеют не-литеральные типы классов.
У нас есть две явные гарантии того, что полное выражение инициализатора является константным выражением, оба из [dcl.constexpr/9]
: a
неявно const
, а полное выражение , а не , являющееся константным выражением, будет ошибкой.
Спецификатор constexpr
, используемый в объявлении объектаобъявляет объект как const.Такой объект должен иметь буквальный тип и должен быть инициализирован.В любом объявлении переменной constexpr
полное выражение инициализации должно быть константным выражением.
Это также означает, что (начиная с C ++ 14), a
не будет инициализироваться нулем ([basic.start.static/2]
, нерелевантные части опущены):
Инициализация констант выполняется, если переменнаяили временный объект со статическим или потоковым сроком хранения инициализируется константным инициализатором ([expr.const]) для объекта.Если постоянная инициализация не выполняется, переменная со статической продолжительностью хранения ([basic.stc.static]) или продолжительностью хранения потока ([basic.stc.thread]) инициализируется нулями ([dcl.init]).
Чтобы убедиться, что a
имеет правильное значение после инициализации, если мы хотим быть действительно тщательными, мы могли бы тогда взглянуть на [intro.execution/9]
:
Каждое вычисление значения и побочный эффект, связанный с полным выражением, секвенируются перед каждым вычислением значения и побочным эффектом, связанным со следующим полным выражением, которое будет оценено.
Поскольку мы знаем, что инициализация a
является полным выражением, мы неявно гарантируем, что a
будет присвоено значение 41
в конце его полного выражения, до следующего полного Выражение (включая другие инициализации) в последовательности оценивается. Объединив это с [expr.const/3]
и [basic.start.static/2]
, мы, таким образом, гарантируем, что (как и в случае с constexpr
), a
можно использовать в константных выражениях, встречающихся после его собственной инициализации, такой как инициализация b
, а также гарантировано, что a == 41 && a != 0
.