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);
}