Подтвердить что ты не робот

Является ли утверждение пригодным для использования в постоянных выражениях?

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

4b9b3361

Ответ 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);
}