16

Summary: nullptr converts to bool, and bool converts to int, so why doesn't nullptr convert to int?

This code is okay:

void f(bool);
f(nullptr);      // fine, nullptr converts to bool

And this is okay:

bool b;
int i(b);        // fine, bool converts to int

So why isn't this okay?

void f(int);
f(nullptr);      // why not convert nullptr to bool, then bool to int?
Daniel Heilper
  • 1,182
  • 2
  • 17
  • 34
KnowItAllWannabe
  • 12,972
  • 8
  • 50
  • 91
  • 2
    What would you expect the conversion to be? – David Heffernan Oct 26 '12 at 18:20
  • 3
    The compiler will only ever do *one* implicit conversion from what you pass to what the function accepts. This applies to essentially all types, not just nullptr's. For example, if you define a type that has a conversion to `char` and try to pass it to a function that takes an `int`, it'll fail even though it supports implicit conversion to `char`, and there's also an implicit conversion from `char` to `int`. – Jerry Coffin Oct 26 '12 at 18:30
  • 1
    @JerryCoffin The compiler will often do more than one implicit conversion. It will only do one user defined conversion, but it can tack on any number of other conversions, according to the rules. There is a rule that at most one conversion can be applied in any given category, and both `nullptr_t` to `bool` and `bool` to various integral types are in the category "Conversion" (see 13.2.2.1.1). – James Kanze Oct 26 '12 at 19:37
  • 3
    i know Bert, and Bert knows Hans and Hans knows Obama. So I know Obama! – Johannes Schaub - litb Nov 04 '12 at 16:15

4 Answers4

30

Because it is exactly the main idea of nullptr.

nullptr was meant to avoid this behavior:

struct myclass {};

void f(myclass* a) { std::cout << "myclass\n"; }
void f(int a) { std::cout << "int\n"; }

// ...

f(NULL); // calls void f(int)

If nullptr were convertible to int this behavior would occur.

So the question is "why is it convertible to bool?".

Syntax-"suggarness":

int* a = nullptr;
if (a) {
}

Which looks way better than:

if (a == nullptr) {
}
Murilo Vasconcelos
  • 4,677
  • 24
  • 27
  • 10
    @David: No, it is. The reason behind `nullptr` is that it does *not* convert to anything other than a pointer type. – Xeo Oct 26 '12 at 18:26
  • @Xeo I think the question, "Why _can't_ it", is different than "Why _doesn't_ it" or "Why _shouldn't_ it". In that case, this answer isn't really an answer. – Seth Carnegie Oct 26 '12 at 18:28
  • @Xeo Read the answer and see if you can find that information in it. – David Heffernan Oct 26 '12 at 18:28
  • @DavidHeffernan not the best answer in the world but still an answer. – Murilo Vasconcelos Oct 26 '12 at 19:02
  • 4
    @SethCarnegie: The question "why can't it" is easily answered with "because the spec says so." Since that's simple, obvious, and completely *useless* in any practical sense, the question clearly is implicitly asking for the *reason* behind forbidding the conversion. – Nicol Bolas Oct 26 '12 at 19:07
  • @NicolBolas I don't think so. The way I read it, the question is why isn't more than one conversion be performed, not what the reasoning is behind not allowing `nullptr` to be converted directly to `int`. – Seth Carnegie Oct 26 '12 at 19:11
  • @MuriloVasconcelos The original answer, at the time I commented, was "Because it is exactly the main idea of nullptr." – David Heffernan Oct 26 '12 at 19:15
  • 2
    @MuriloVasconcelos in your example, `if (a)` is converting an `int*` to a `bool`, not `nullptr` to a `bool`. – Seth Carnegie Oct 26 '12 at 19:16
  • @SethCarnegie: No, that is a much more general question which has nothing to do with `nullptr` specifically, as it applies to *all* conversions. – Nicol Bolas Oct 26 '12 at 19:26
  • @NicolBolas I disagree, even though it is a more general question, he just happened to ask it with `nullptr` as the case-study or whatever you call it. But whatever, he'll accept whichever answer is helpful to him. – Seth Carnegie Oct 26 '12 at 19:29
  • I was able to convert `nullptr` to `int` via `static_cast(reinterpret_cast(static_cast(nullptr)))` which follows the allowed conversions according to the standard. But it is a terrible idea, and you should never do it! You can run it [here](https://ideone.com/AQTI2a). – callyalater Sep 09 '19 at 23:30
18

In §4.1 of the Standard, it says how conversions are performed:

Standard conversions are implicit conversions with built-in meaning. Clause 4 enumerates the full set of such conversions. A standard conversion sequence is a sequence of standard conversions in the following order:

— Zero or one conversion from the following set: lvalue-to-rvalue conversion, array-to-pointer conversion, and function-to-pointer conversion.

— Zero or one conversion from the following set: integral promotions, floating point promotion, integral conversions, floating point conversions, floating-integral conversions, pointer conversions, pointer to member conversions, and boolean conversions.

— Zero or one qualification conversion.

So the compiler only does "zero or one conversion" of some, none, or all of each of the above types of conversions, not arbitrarily many. And that's a really good thing.

Community
  • 1
  • 1
Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249
  • +1: tite answer, Seth. It is hard for me to tell, but are the conversions categories listed here (the three specific categorizations) mutually exclusive *to each other* as well? The standard just reads a little gray to me on that (or i'm not reading it right, which wouldn't be the first time). – WhozCraig Oct 26 '12 at 18:30
  • 1
    @WhozCraig no, they are each done in order, either none, one, two, or all three; the are inclusive. Using aschepler's example: `void f(const int*); int my_array[10]; f(my_array);` converts the array to a pointer and then the pointer to a `const` pointer. – Seth Carnegie Oct 26 '12 at 18:31
  • Ok, then they at least appear to waterfall though, which the standard does spell out (i.e. no going back up the list once one conv is filled; you can only go down. I think..) – WhozCraig Oct 26 '12 at 18:34
  • @WhozCraig yes exactly. If it could start over at previous steps, that would mean that one of them could be done more than once, which is against what it says. – Seth Carnegie Oct 26 '12 at 18:35
2

To understand why is this happening, you should understand how to use nullptr. Check these links bellow:

I hope it helps.

Community
  • 1
  • 1
Rontogiannis Aristofanis
  • 8,883
  • 8
  • 41
  • 58
0

The keyworkd nullptr is introduced in c++11 because multiple definition of the C NULL, and it confuses when overloading a function with int arguments and NULL.

#define NULL 0
#define NULL (void*)0

In the bible The C++ Programming Language (4th), page 270

The pointer-to-bool conversion is useful in conditions, but confusing elsewhere.

So I think nullptr_t varible convert to int is not allowed because that's the reason why it exists, but it can be used as a test condition like bool variables.

chunyang.wen
  • 204
  • 1
  • 9