The cppreference page for [[assume]]
says that:
[[assume( expression )]]
[...] the expression is not evaluated (but it is still potentially evaluated).
This wording confuses me. Is cppreference wrong here?
Why would it be potentially evaluated if it's not evaluated? Isn't it an unevaluated operand like the expression in sizeof
?
If not, what are the consequences?
The C++ standard says virtually the same:
The expression is not evaluated. [...]
[- Note 1: The expression is potentially evaluated ([basic.def.odr]). [...] - end note]
Crucially, the standard says that the expression is not evaluated, however the expression is not an unevaluated operand. The wording is carefully chosen and very important.
An expression or conversion is potentially evaluated unless it is an unevaluated operand ([expr.context]), a subexpression thereof, or a conversion in an initialization or conversion sequence in such a context.
As a result [[assume]]
enjoys none of the privileges that unevaluated operands have. To name one example, we cannot refer to non-static data members directly:
struct S { int x; };
int main() {
// OK, referring to non-static data members in decltype is possible,
// because its expression is an unevaluated operand
decltype(S::x) x;
// ill-formed, illegal use of S::x in this context
[[assume(S::x > 0)]];
}
It only makes sense that [[assume]]
is potentially evaluated, because it informs the compiler that a certain runtime expression would evaluate to true
, if it was evaluated, hypothetically.
The expression must be something that the compiler could potentially evaluate, even if it never does.