29

I don't understand why following code compiles ?

int main()
{
     //int a = nullptr;  // Doesn't Compile
     //char b = nullptr; // Doesn't Compile
       bool c = nullptr; // Compiles

       return 0;
}

whereas the commented section doesn't.


I've already gone through this and this.

Both bool and nullptr are keywords, so what's unique about the other data types?

Community
  • 1
  • 1
P0W
  • 46,614
  • 9
  • 72
  • 119
  • 4
    This seems relevant: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#654 – Johannes Schaub - litb Feb 25 '14 at 13:30
  • 1
    *"Both bool and nullptr are keywords, so what's unique about the other data types?"* I would be glad if you clarified why the fact that they are both keywords would make a difference. If you said `std::nullptr_t p; int a = p; bool c = p;` would that make any difference for you? – Johannes Schaub - litb Feb 25 '14 at 14:11
  • 1
    @JohannesSchaub-litb Sorry for confusion, but my concern was why `nullptr` doesn't convert to basic data type i.e `char`, `int` ? – P0W Feb 25 '14 at 14:17
  • The question and the answers are applicable to C++11, but out-of-date for any later version of the language specification. Since C++14 this impicit conversion in **NOT** allowed outside of direct-initialization contexts anymore. The above initialization does **NOT** compile. – AnT stands with Russia Dec 16 '21 at 19:47

4 Answers4

42

For the same reason as

if( p ) { ... }

compiles: any value of basic type converts implicitly to boolean, with 0 converting to false and any other value to true.

Originally basic type values had to convert to bool for C compatibility. C didn't originally have a bool type, but any numerical expression could be used as a boolean (with the 0 == false convention). And now we're caught in the backward compatibility tangle. nullptr has to support idiomatic constructs such as if(p), especially for the cases where old code's literal 0 or NULL is replaced with nullptr. E.g. code like if(p) can result from a macro expansion, or in template code.


Addendum: the technical how of why nullptr doesn't convert to e.g. int.

Since nullptr converts implicitly to bool, and bool (unfortunately) converts implicitly to int, one could expect that nullptr should also convert to int. But the point of nullptr is that it should behave as a pointer value. And while pointers do convert implicitly to bool, they do not convert implicitly to numerical types.

Arranging such a restriction for a user-defined type is however not entirely straightforward. An operator bool conversion will be invoked for conversion to int, if it's present. One C++11 solution to enfore the restriction, is to make the conversion operator a template, restricted by a std::enable_if, as follows:

#include <type_traits>  // std::enable_if, std::is_same

struct S
{
    template< class Type >
    operator Type* () const { return 0; }

    template<
        class Bool_type,
        class Enabled = typename std::enable_if<
            std::is_same<Bool_type, bool>::value, void
            >::type
        >
    operator Bool_type () const { return false; }
};

auto main() -> int
{
    bool const              b   = S();      // OK.
    double const*  const    p   = S();      // OK.
    int const               i   = S();      // !Doesn't compile.
}
Jules
  • 14,841
  • 9
  • 83
  • 130
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • 7
    I don't see why this provides the reason. `p` is not a null pointer constant. Why do you want to write literally `if(nullptr) { ... }`? – Johannes Schaub - litb Feb 25 '14 at 12:00
  • 1
    @JohannesSchaub-litb: your comment is apparently **meaningless**. would you care to expand on (1) why you think I would want write literally `if(nullptr){...}`, and (2) what the heck that has to do with anything? for that matter, also the baffling (3) "p is not a null pointer constant", where on earth do you get that from? it's just ... meaningless. i have no words. – Cheers and hth. - Alf Feb 25 '14 at 12:17
  • 1
    I am sorry for not checking exactly what you wrote and what I thought before commenting (which doesn't justify a downvote of someone else... they should think for themselfs instead of just voting because of a negativy comment appearing). Well, `p` could be a null-pointer constant, true (if it is of type `nullptr_t`, just like `nullptr` or a constant integer). So I shall change my question to: *Why must any value of basic type convert to bool?* – Johannes Schaub - litb Feb 25 '14 at 13:02
  • 3
    I definitely see the obvious need for pointers converting to bool (independent of C compatibility even), and also for integers (for C compatibility). But `nullptr` and `nullptr_t` is unique to C++, so I don't quite see the reason here (which is the reason why I formulated my first comment the way it is). – Johannes Schaub - litb Feb 25 '14 at 13:08
  • 1
    @JohannesSchaub-litb: Originally basic type values had to convert to `bool` for C compatibility. C didn't originally have a `bool` type, but any numerical expression could be as a boolean (with the 0 == false convention). And now we're caught in the backward compatibility tangle. `nullptr` has to support idiomatic constructs such as `if(p)`, especially for the cases where old code's literal `0` or `NULL` is replaced with `nullptr`. E.g. it can result from a macro expansion. – Cheers and hth. - Alf Feb 25 '14 at 13:11
  • I see. It would be a much better answer if you would have posted that as your text IMO. – Johannes Schaub - litb Feb 25 '14 at 13:14
  • 2
    Technically `nullptr_t` need not convert to `bool`. It would be a bit strange, in that `if (nullptr)` would fail to compile while `if( ptr = nullptr )` would compile, but... *however* if you wrote a `template` function where one of the arguments was pointer-like, being able to pass `nullptr` would be nice, and the `if` clauses would then occur. – Yakk - Adam Nevraumont Feb 25 '14 at 14:22
  • 5
    I hope `if( ptr = nullptr )` gives a warning. – Vladimir F Героям слава Feb 25 '14 at 14:25
  • @VladimirF: E.g. `while( cin >> x )` is idiomatic code, and the safe way to do things. So to avoid sillywarnings on such constructs I would personally turn that warning off, if a compiler had it on by default. That said, I'm not sure what the subject is now. ;-) – Cheers and hth. - Alf Feb 25 '14 at 15:31
  • 5
    @Cheersandhth.-Alf an assignment in an `if` that generates a dead branch (or a tautological `if`) is **often** a sign that `=` was used instead of `==`. – Yakk - Adam Nevraumont Feb 25 '14 at 19:30
19

C++11 §4.12 Boolean conversions

A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a prvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true. A prvalue of type std::nullptr_t can be converted to a prvalue of type bool; the resulting value is false.

It's true that nullptr is a keyword, but it's a null pointer literal, not the same role as bool. Think about the boolean literals, true and false are also keywords.

Community
  • 1
  • 1
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • 1
    This answer does not go into the rationale of the rules, the "why" requested by the OP. I.e. it's not even an answer. However, it's not incorrect. – Cheers and hth. - Alf Feb 25 '14 at 12:36
  • 2
    @Cheersandhth.-Alf I answered two things: <1> Why `nullptr` can be converted to a `bool`. <2> Why it can be used in the right hand side of `=` syntactically while apparently you can't put `bool` (which is also a keyword) there. Because `nullptr` is a literal, just like `42` or `true` (another keyword that is a literal). Perhaps we have different opinions of what the OP asks mainly, but I think my answer answers at least some of the OP's question. – Yu Hao Feb 25 '14 at 13:18
  • 2
    Uhm, as i see it <1>, the "why", is not answered. But <2>, about a confusion about types versus values, may be exactly what the OP was/is asking about. I didn't see that, sorry. – Cheers and hth. - Alf Feb 25 '14 at 13:49
  • 2
    As the asker didn't specify his compiler, most probably his *"Why “bool c = nullptr ;” compiles"* was not intended as "Why does my compiler accept this? Satisfying customers? Just compliance?" (which your reply "because the standard requires that " would indeed answer), but the question probably was "Why does the Standard require this somewhere?", which you don't answer at all. And I don't understand what "... but it's a null pointer literal, not the same role as bool" is intended to say. I would be glad if you clarified that part. – Johannes Schaub - litb Feb 25 '14 at 13:54
  • @JohannesSchaub-litb I didn't answer the question because I didn't think it was the main question at first, but then after @Cheers and hth. - Alf updates his answer, I don't think I can provide a better answer on this than his answer. I was emphasizing that `nullptr` is not the same kind of keyword than `bool`, its role is a literal of pointer type, just like `true` for `bool` type, but as I just saw OP's comment, it's not what he asked mainly. I would definitely update my answer to better suit OP's clarified question if I can think of a different view of @Alf's and your answer. – Yu Hao Feb 25 '14 at 14:37
5

In http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#654 , Jason Merril argues

Anything we can do with an arbitrary pointer, we ought to be able to do with nullptr_t as well.

I think the following (slightly artificial) example supports that argument (although I am not totally sure if it was intended for this case)

template<typename T, typename P>
void safeProcess(T pointer, P &processor) {
  bool isNonNull(pointer);
  if(isNonNull) {
    processor.process(pointer);
  }
}

Which would allow passing nullptr along with other pointer types compatible with whatever processor.process accepts.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
0

C++11 corrects this by introducing a new keyword to serve as a distinguished null pointer constant: nullptr. It is of type nullptr_t, which is implicitly convertible and comparable to any pointer type or pointer-to-member type. It is not implicitly convertible or comparable to integral types, except for bool. While the original proposal specified that an rvalue of type nullptr should not be convertible to bool, the core language working group decided that such a conversion would be desirable, for consistency with regular pointer types. The proposed wording changes were unanimously voted into the Working Paper in June 2008.[2]

For backwards compatibility reasons, 0 remains a valid null pointer constant.

char *pc = nullptr;     // OK
int  *pi = nullptr;     // OK
bool   b = nullptr;     // OK. b is false.
int    i = nullptr;     // error
iampranabroy
  • 1,716
  • 1
  • 15
  • 11