Макрос assert
из <cassert>
обеспечивает краткий способ проверки выполнения условия. Если аргумент оценивается как true
, он не должен иметь никаких дальнейших эффектов. Однако можно ли в этом случае также использовать его вызов внутри константного выражения?
Можно ли использовать assert в постоянных выражениях?
Ответы (1)
Это было рассмотрено LWG 2234, на который снова обратили внимание после того, как были введены ослабленные ограничения на constexpr
функции.
Предлагаемое решение:
Эта формулировка относится к N3936.
Внесите следующее новое определение в существующий список в 17.3 [определения]:
подвыражение константы [defns.const.subexpr]
выражение, оценка которого как подвыражения условного выражения CE (5.16 [expr.cond]) не помешала бы CE быть основным константным выражением (5.20 [expr.const ]).
Включить новый абзац после 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);
}
e
может быть самим e
, не так ли? (например, сравните §1.9/10) Или вы на самом деле имеете в виду, что CS вообще не является частью CE?
- person Columbo; 25.05.2015
<=
, а не <
) - - это был второй пункт, на который я хотел обратить внимание. Во-первых, операторы внутри функции не являются подвыражениями выражения вызова функции. -- о, и с Днем полотенец ;)
- person dyp; 25.05.2015
f()
без лексического появления внутри него.
- person Columbo; 25.05.2015
f
являются подвыражениями f()
из этого абзаца: здесь говорится об оценке выражений, но не говорится, что они становятся/являются частью из f()
.
- person dyp; 25.05.2015
e1
выражения e
является непосредственным подвыражением, если не существует подвыражения e2
выражения e
, такого что e1
является подвыражением e2
. можно найти в [except.spec]/12. Моя вина.
- person Columbo; 03.02.2016