Issue 2234: assert() should allow usage in constant expressions (original) (raw)
This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++17 status.
2234. assert()
should allow usage in constant expressions
Section: 19.3 [assertions] Status: C++17 Submitter: Daniel Krügler Opened: 2013-01-12 Last modified: 2017-07-30
Priority: 2
View all other issues in [assertions].
View all issues with C++17 status.
Discussion:
It is unclear from the current specification whether assert()
expressions can be used in (potential) constant expressions. As an example consider the implementation of a constexpr
function:
#include
template<class T, unsigned N> struct array { T data[N]; constexpr const T& operator[](unsigned i) const { return assert(i < N), data[i]; } };
int main() { constexpr array<int, 3> ai = {1, 2, 3}; constexpr int i = ai[0]; int j = ai[0]; // constexpr int k = ai[5]; }
The first question is whether this program is guaranteed well-formed? A second question is whether is would guaranteed to be ill-formed, if we uncomment the last code line in main()
?
The wording in 19.3 [assertions] doesn't add anything significant to the C99 wording. From the C99 specification (7.2 p1 and 7.2.1.1 p2) we get already some valuable guarantees:
- The expression
assert(e)
is avoid
expression for all expressionse
independent of the definition ofNDEBUG
. - If
NDEBUG
is defined,assert(e)
is equivalent to the expressionvoid()
(or anything that cannot be distinguished from that).
The current wording does not yet guarantee that assert
expressions can be used in constant expressions, but all tested implementations (gcc, MSVC) would already support this use-case. It seems to me that this should be possible without giving assert
a special meaning for the core language.
As a related comment it should be added, that there is a core language proposalthat intents to relax some current constraints for constexpr
functions and literal
types. The most interesting one (making void
a literal types and allowing for expression-statements) would simplify the motivating example implementation of operator[]
to:
constexpr const T& operator[](unsigned i) const { assert(i < N); return data[i]; };
[2013-03-15 Issues Teleconference]
Moved to Open.
We are still gaining experience with constexpr
as a language feature, and there may be work in Evolution that would help address some of these concerns. Defer discussion until we have a group familiar with any evolutionary direction.
[2014-06-08, Daniel comments and suggests wording]
After approval of N3652,void
is now a literal type and constexpr
functions can contain multiple statements, so this makes the guarantee that assert
expressions are per-se constexpr
-friendly even more relevant. A possible wording form could be along the lines of:
For every core constant expression e of scalar type that evaluates to
true
after being contextually converted tobool
, the expressionassert(_e_)
shall be a prvalue core constant expression of typevoid
.
Richard Smith pointed out some weaknesses of this wording form, for example it would not guarantee to require the following example to work:
constexpr void check(bool b) { assert(b); }
because b
is not a core constant expression in this context.
He suggested improvements that lead to the wording form presented below (any defects mine).
[Lenexa 2015-05-05]
MC : ran into this
Z : Is it guaranteed to be an expression?
MC : clarifies that assert runs at runtime, not sure what it does at compile time
STL : c standard guarantees its an expression and not a whole statement, so comma chaining it is ok
HH : Some implementations work as author wants it to
STL : also doing this as constexpr
DK/STL : discussing how this can actually work
HH : GCC 5 also implements it. We have implementor convergence
MC : Wants to do this without giving assert a special meaning
STL : NDEBUG being defined where assert appears is not how assert works. This is bug in wording. Should be "when assert is defined" or something like that. ... is a constant subexpression if NDEBUG is defined at the point where assert is last defined or redefined."
Would like to strike the "either" because ok if both debug or assertion is true. We want inclusive-or here
MC : is redefined needed?
STL : my mental model is its defined once and then redefined
HH : wants to up to P2
Z/STL : discussing how wording takes care of how/when assert is defined/redefefined
STL/WB : discussing whether to move to ready or review. -> Want to move it to ready.
ask for updated wording
p3 -> p2
plan to go to ready after checking wording
[Telecon 2015-06-30]
HH: standardizing existing practice
MC: what about the comment from Lenexa about striking "either"?
HH: all three implementations accept it
MC: update issue to strike "either" and move to Tentatively Ready
Proposed resolution:
This wording is relative to N3936.
Previous resolution [SUPERSEDED]:
- Introduce the following new definition to the existing list in [definitions]: [_Drafting note_: If LWG 2296(i) is accepted before this issue, the accepted wording for the new definition should be used instead — _end drafting note_]
constant subexpression [defns.const.subexpr]
an expression whose evaluation as subexpression of a conditional-expression CE (7.6.16 [expr.cond]) would not prevent CE from being a core constant expression (7.7 [expr.const]).
- Insert a new paragraph following 19.3 [assertions] p1 as indicated:
-?- An expression
assert(_E_)
is a constant subexpression (3.15 [defns.const.subexpr]), if either
NDEBUG
is defined at the point whereassert(_E_)
appears, or_E_
contextually converted tobool
(7.3 [conv]), is a constant subexpression that evaluates to the valuetrue
.
- Introduce the following new definition to the existing list in [definitions]: [_Drafting note_: If LWG 2296(i) is accepted before this issue, the accepted wording for the new definition should be used instead — _end drafting note_]
constant subexpression [defns.const.subexpr]
an expression whose evaluation as subexpression of a conditional-expression CE (7.6.16 [expr.cond]) would not prevent CE from being a core constant expression (7.7 [expr.const]).
- Insert a new paragraph following 19.3 [assertions] p1 as indicated:
-?- An expression
assert(_E_)
is a constant subexpression (3.15 [defns.const.subexpr]), ifNDEBUG
is defined at the point whereassert(_E_)
appears, or_E_
contextually converted tobool
(7.3 [conv]), is a constant subexpression that evaluates to the valuetrue
.