Можно ли использовать assert в постоянных выражениях?

assertМакро от <cassert> обеспечивает краткий способ гарантировать, что условие выполнено. Если аргумент оценивается как true, это не должно иметь никаких дальнейших последствий. Однако может ли его вызов также использоваться внутри константного выражения в этом случае?

1 ответ

Решение

Это было решено LWG 2234, на который снова обратили внимание после смягчения ограничений на constexpr функции были введены.

Предлагаемое решение:

Эта формулировка относится к N3936.

  1. Введите следующее новое определение в существующий список в 17.3 [определения]:

    постоянное подвыражение [defns.const.subexpr]

    выражение, оценка которого как подвыражение условного выражения CE (5.16 [expr.cond]) не помешает CE быть выражением ядра-константы (5.20 [expr.const]).

  2. Включить новый абзац после пункта 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);
}
Другие вопросы по тегам