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

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


person Columbo    schedule 25.05.2015    source источник
comment
в настоящее время активна ошибка gcc   -  person TemplateRex    schedule 19.01.2016


Ответы (1)


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

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

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

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

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

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

  2. Включить новый абзац после 19.3 [утверждения] п.1, как указано:

    -?- Выражение assert(E) является константным подвыражением ( [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(E) является постоянным подвыражением, если либо определено 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);
}
person Columbo    schedule 25.05.2015
comment
Терминология немного странная: постоянное подвыражение CS постоянного выражения CE не обязательно должно быть подвыражением CE и вообще не должно быть подвыражением. (полное выражение). - person dyp; 25.05.2015
comment
@dyp Подвыражение e может быть самим e, не так ли? (например, сравните §1.9/10) Или вы на самом деле имеете в виду, что CS вообще не является частью CE? - person Columbo; 25.05.2015
comment
Не уверен, есть ли определение подвыражения? Насколько я могу судить, §1.9p10 определяет полное выражение, а не подвыражение (хотя формулировка другого выражения может указывать на то, что на самом деле подвыражением является <=, а не <) - - это был второй пункт, на который я хотел обратить внимание. Во-первых, операторы внутри функции не являются подвыражениями выражения вызова функции. -- о, и с Днем полотенец ;) - person dyp; 25.05.2015
comment
@dyp Определения нет, но я предполагаю, что то, что вы упомянули, действительно так. Ко второму пункту: Да, я думаю, мне нужно переформулировать это. Но как насчет /11: Оценка полного выражения может включать оценку подвыражений, которые не являются лексически частью полного выражения. Это указывает на то, что выражение может быть подвыражением f() без лексического появления внутри него. - person Columbo; 25.05.2015
comment
Я не уверен, что можно сделать вывод, что выражения внутри функции f являются подвыражениями f() из этого абзаца: здесь говорится об оценке выражений, но не говорится, что они становятся/являются частью из f(). - person dyp; 25.05.2015
comment
@dyp Может быть, нам нужно более тонко различать лексические и оценочные подвыражения. Я зарегистрирую проблему. - person Columbo; 19.01.2016
comment
@dyp Похоже, что термин подвыражение последовательно используется как ‹, а не ‹=, например: подвыражение e1 выражения e является непосредственным подвыражением, если не существует подвыражения e2 выражения e, такого что e1 является подвыражением e2. можно найти в [except.spec]/12. Моя вина. - person Columbo; 03.02.2016