This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 114a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-04-18


963. Comparing nullptr with 0

Section: 7.6.9  [expr.rel]     Status: CD2     Submitter: Mike Miller     Date: 8 September, 2009

[Voted into WP at March, 2010 meeting.]

The current wording of the draft does not indicate what is supposed to happen when an rvalue of type std::nullptr_t is compared with an integral null pointer constant. (This could occur, for example, in template code like

    template<typename T> void f(T t) {
        if (t == 0) // ...
    }

in a call like f(nullptr) -- presumably the body of the template was written before nullptr became available and thus used an integral null pointer constant.) Because an integral null pointer constant can be converted to std::nullptr_t (7.3.12 [conv.ptr] paragraph 1), one might expect that 0 would be converted to std::nullptr_t and the two operands would compare equal, but 7.6.9 [expr.rel] paragraph 2 does not handle this case at all, leaving it as undefined behavior.

The current situation is more well-defined (but perhaps not better) with respect to the conditional operator. 7.6.16 [expr.cond] paragraphs 3-6 make it ill-formed to have std::nullptr_t and 0 as the second and third operands. Again, it's not too hard to imagine a legacy function template like

    template<typename T> void f(T t, bool b) {
        T t = b ? t : 0;
    }

which would be ill-formed under the current wording of 7.6.16 [expr.cond].

Either 7.6.9 [expr.rel] and 7.6.10 [expr.eq] should be changed to make this combination of operands ill-formed, or those two sections should be changed to give the comparison defined semantics and 7.6.16 [expr.cond] should be changed to make those operands well-formed.

Proposed resolution (October, 2009):

  1. Change 7.6.9 [expr.rel] paragraph 2 as follows:

  2. The usual arithmetic conversions are performed on operands of arithmetic or enumeration type. Pointer conversions (7.3.12 [conv.ptr]) and qualification conversions (7.3.6 [conv.qual]) are performed on pointer operands (or on a pointer operand and a null pointer constant, or on two null pointer constants, at least one of which is non-integral) to bring them to their composite pointer type. If one operand is a null pointer constant, the composite pointer type is std::nullptr_t if the other operand is also a null pointer constant or, if the other operand is a pointer, the type of the other operand. Otherwise...
  3. Change 7.6.16 [expr.cond] bullet 6.3 as follows: