assert
-macro от <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(
E)
является константным подвыражением ([defns.const.subexpr]), если либо
NDEBUG
определяется в точке, где появляется утверждение (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(
E )
является константным подвыражением, если определен либо NDEBUG
, либо сам аргумент является константным подвыражением и оценивается как true
. Это означает, что вызов assert
также может быть стандартным постоянным выражением bog.
Хорошо сформировано следующее:
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);
}