8

I tested the following code with 3 compilers and got 3 different results: error, warning and ok.

  • GCC (5.3): error: invalid user-defined conversion from ‘std::nullptr_t’ to ‘const Thing&’
  • Clang (3.8): warning: implicit conversion of nullptr constant to 'bool'
  • MSVC (14.1): no error, no warning

Which compiler is correct? I know it's a trivial conversion between a pointer type and bool. But what's about std::nullptr_t and bool?

(In the end, Clang and MSVC are both fine with the code. Clang is a little bit more verbose in a positive way.)

struct Thing
{
    Thing(bool) {}
};

void addThing(const Thing&){}

int main()
{
    addThing(nullptr); // warning or error on this line
}
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
sven
  • 107
  • 6

1 Answers1

9

This is invalid. According to the rule of boolean conversions:

A prvalue of type std::nullptr_t, including nullptr, can be converted to a prvalue of type bool in context of direct-initialization. The resulting value is false.

Quotes from the standard, §7.14/1 Boolean conversions [conv.bool]

For direct-initialization, a prvalue of type std​::​nullptr_­t can be converted to a prvalue of type bool; the resulting value is false.

The conversion is only allowed for direct-initialization, but not copy-intialization, which including the case for passing argument to a function by value. e.g.

bool b1 = nullptr; // invalid
bool b2 {nullptr}; // valid

So GCC is correct. But Clang is not wrong either; the standard only requires the compiler to "issue a diagnostic" when program is ill-formed, so it must tell you something happens, after that it could do anything.

See Does the C++ standard specify that for some cases the compiling should fail with an error?

Community
  • 1
  • 1
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • Am I the only one bothered by the logical inconsistency here? (not the answer itself). I'm sure it was enforced for other reasons, but this *really* strikes me as a case where neither should work in the absence of a `_cast` operator. – Brett Hale May 05 '17 at 11:31
  • 1
    @BrettHale My interpretation is that `nullptr` can only be implicitly converted to null pointer (of any pointer type and any pointer to member type). The conversion to `bool` must be explicit, but still allowed (for consistency of other pointers?) . – songyuanyao May 05 '17 at 11:37
  • 1
    @Brett Hale I don't see it as inconsistent. Calling a constructor explicitly, surprise surprise, calls constructors which have been marked explicit, which is exactly one of the things that static cast will do! These are primitive types so they don't literally have constructors but the idea is the same. – Nir Friedman May 05 '17 at 11:52
  • 1
    The comments about clang are correct in one language-lawyer sense (the standard only requires issuing a diagnostic, not failure to compile). However, this conveniently side-steps the fact that clang is actually permitting an invalid conversion. At the least, doing this (permitting a conversion that is invalid according to the standard, and then issuing a warning about it) is a quality-of-implementation concern. There are plenty of behaviours that may be legally correct, even if reasonable people other than lawyers expect otherwise, and this is an example, – Peter May 05 '17 at 12:46
  • @songyuanyao - I understand the idea as a concept of orthogonality when converting types. e.g., `NULL` essentially *had* to evaluate as `(0)`. The introduction of `nullptr` as a `std::nullptr_t` type really has to evaluate the same way as `NULL`. It's just that the mapping of any 'null' type to a boolean doesn't make a lot of sense. But I completely understand it from a practical perspective... I was just in a puritanical mood about typing :) – Brett Hale May 05 '17 at 13:04
  • @Peter Clang chose this for the consistency? Both raw pointers and `NULL` (`0`) could be implicitly converted to `bool`. – songyuanyao May 05 '17 at 13:31
  • @BrettHale Yes I understand. I guess it's for the consistency, because both raw pointers and `NULL` (`0`) could be implicitly converted to `bool`. Trade-off is always not an easy thing. – songyuanyao May 05 '17 at 13:40
  • @songyuanyao - that's as may be. But, for the end user, it is not particularly helpful to permit a conversion which is invalid according to the standard. This is a compiler's equivalent of deeming that someone is allowed to pull your pants down if they warn you first. There are ways to raise such things for consideration as a change to the standard. – Peter May 05 '17 at 22:09