Document No: P1401r1
Author: Andrzej Krzemieński
Reply-to: akrzemi1 (at) gmail (dot) com
This paper proposes to allow conversions from integral types to type
bool in contextually converted constant expression of type
Extended the discussion and problem analysis. Outlined the reange of possible changes. Not proposing wording anymore: the goal is to obtain the direction from EWG first.
Clang currently fails to compile the following program, and this behavior is Standard-compliant:
This is because, as currently specified, narrowing is not allowed in contextual conversion to
bool in core constant expressions. If compilers were standard-compliant, even the following code would be ill-formed.
All these situations can be fixed by typing a
static_cast to type
bool or comparing the result to 0, but the fact remains that this behavior is surprising. For instance, using run-time equivalents of the above constructs compiles and executes fine:
Note that the proposal only affects the contextual conversions to
bool: it does not affect implicit conversions to
bool in other contexts.
The no-narrowing requirement was added in [CWG 2039], which indicates it was intentional. However, the issue documentation does not state the reason.
The no-narrowing requirement looks justified in the context of
noexcept specifications, where the “double
noexcept” syntax is so strange that it can be easily misused. For instance, if I want to say that my function
f() has the same
noexcept specification as function
g(), it doesn’t seem impossible that I could mistakenly type this as:
To the uninitiated this looks reasonable; and it compiles. Also, if
g() is a
constexpr function, the following works as well:
The no-narrowing requirement helps minimize these bugs, so it has merit. But other contexts, like
static_assert, are only victims thereof.
The definition of contextually converted constant expression of type
bool ([expr.const]/7) is used in four places in the standard:
requires-clause does not use the definition, as it requires that the expression “shall be a constant expression of type
bool” ([temp.constr.atomic]/3). The problems caused by the contextually converted constant expression of type
bool are mostly visible in the first two cases. In case of
explicit(bool) we expext a type trait to be used as an expression.
Similarly, in the case of
noexcept(bool) we only expect a type trait or a
The following table illustrates where compilers allow a conversion to bool in a contextually converted constant expression of type
bool against the C++ requirements:
* MSVC accepts the code but issues a warning even in
** Feature not implemented.
Accepting this proposal would be to some extent standardizing the existing practice among compiler vendors.
The following table lists types that are contextually convertible to type
|type||allowed in constant expr||
|class with conversion to
|class with conversion to a built-in type convertibel to
||as per rules below||as per below rules|
|object/function pointer||no||not null|
|pointer to member||no||not null|
|integral type||no, except for 0 and 1||not zero|
|floating-point type||no||not plus/minus zero|
|unscoped enumeration||no, except for 0 and 1||not zero|
The problem, which this proposal is trying to fix, has only been reported when conversions from integral types or unscoped enumeraiotn types are involved, as for these types such conversion has practical and often used meaning:
We have never encountered a need to check if a floating-point value is exactly +/-0 in this way. Technically, checking a pointer has a meaning: “is it really pointing to some object/function”, but it is more difficult to imagine a practical use case for it in contextually converted constant expression of type
Some have suggested that a conversion to
bool in general should not be considered narrowing, that
bool should not be treated as a small integral type, and that the conversion to
bool should be treated as a request to classify the states of the object as one of the two categories.
We do not want to go there. Even this seemingly correct reasoning can lead to bugs like this one:
If the feature that prevents narrowing conversions can detect this bug, we would like to use this opportunity.
boolin constant expressions
Another situation brought up while discussing this problem was if the following code should be correct:
In constant expressions the situation is different, because whether a conversion is narrowing or not depends not only on the types but also on the velaues, which are known at compile-time. We think that after [P0907r4] was adopted, and
bool has a well defined representation, conversion from
true is now defined as non-narrowing.
As described in [LWG 3011], currently macro
assert() from the C Standard Library only allows expressions of scalar types, and does not support the concept of expressions “contextually converted to
bool”. We believe that this issue does not interact with our proposal. For instance, the following example works even under the C definition of macro
But it stops working if we change
There is a two-dimensional space of possible solutions to this problems with two extremal solutions being:
bool. (This compromizes the solution in [CWG 2039], whatever its intent was.)
The two “degrees of freedom” in the solution space are:
boolis used; e.g., only in
boolonly from a subset of types implicitly convertible to
bool, e.g., only integral and scoped enumeration types.
In fact, relaxing only
if constexpr, only for integral and scoped enumeration types solves all issues that have been reported by users that we are aware of.
We request guidance from EWG on which approach to adopt.
Jason Merrill originally reported this issue in CWG reflector. Tomasz Kamiński reviewed the paper and suggested improvements.
Members of EWGI significantly improved the quality of the paper.
[CWG 2039] Richard Smith, “Constant conversions to
[LWG 3011] Jonathan Wakely, “Requirements for
assert(E) inconsistent with C”.
[WG14 N2207] Martin Sebor, Jonathan Wakely, Florian Weimer, “Assert Expression Problematic For C++”.
[P0907r4] JF Bastien, “Signed Integers are Two’s Complement”.