Можно ли использовать assert в постоянных выражениях?
assert
Макро от <cassert>
обеспечивает краткий способ гарантировать, что условие выполнено. Если аргумент оценивается как true
, это не должно иметь никаких дальнейших последствий. Однако может ли его вызов также использоваться внутри константного выражения в этом случае?
1 ответ
Это было решено LWG 2234, на который снова обратили внимание после смягчения ограничений на constexpr
функции были введены.
Предлагаемое решение:
Эта формулировка относится к N3936.
Введите следующее новое определение в существующий список в 17.3 [определения]:
постоянное подвыражение [defns.const.subexpr]
выражение, оценка которого как подвыражение условного выражения CE (5.16 [expr.cond]) не помешает CE быть выражением ядра-константы (5.20 [expr.const]).
Включить новый абзац после пункта 19.3 [утверждения] p1, как указано:
-?- Выражение
assert(
Е)
является постоянным подвыражением ( [defns.const.subexpr]), если либо
NDEBUG
определяется в точке, где появляется assert(E), илиE контекстно преобразуется в
bool
(4 [conv]), является постоянным подвыражением, которое оценивает значениеtrue
,
Постоянные подвыражения
Эта резолюция ввела понятие постоянного подвыражения - по существу, выражение, которое не является (обязательно) постоянным выражением само по себе, но может использоваться внутри него. Рассмотрим для примера
constexpr void f() {
int i = 0;
++i;
}
++i
не является константным выражением, поскольку оно изменяет объект, время жизни которого началось вне этого выражения (§5.20/(2.15)). Тем не менее, выражение f()
полностью является константным выражением, потому что предыдущий пункт не применяется - i
жизнь начинается в f
, следовательно ++i
является постоянным подвыражением, так как ++i
не мешает f()
из постоянного выражения.
А также assert
?
Вторая часть резолюции гарантирует, что assert(
Е)
является постоянным подвыражением, если либо NDEBUG
определяется или аргумент сам является постоянным подвыражением и оценивает true
, Это подразумевает, что призыв к assert
также может быть стандартным константным выражением.
Следующее правильно сформировано:
constexpr int check(bool b) {
assert(b);
return 7;
}
constexpr int k = check(true);
b
является постоянным подвыражением и оценивает true
в вызове check(true)
отсюда assert(b)
является постоянным подвыражением и поэтому не мешает check(true)
от того, чтобы быть одним.
Конечно, та же ловушка, что и с static_assert
в шаблонах возможно. При условии NDEBUG
не определено, это определение неправильно сформировано, согласно §7.1.5/5 не требуется никакой диагностики:
constexpr void fail() {
assert(false);
}