I'm using native C++ with Visual Studio 2019 16.11.8. I don't understand this: whis can the false keyword be used as NULL (or nullptr)? Below the test code:

bool test(bool* pb)
{
    if (NULL != pb)
        return *pb;
    else
        return false;
}

void main()
{
    test(false); // compiles (not what I was expecting)
    test(true); // won't compile: error C2664: 'test' : cannot convert parameter 1 from 'bool' to 'bool *'
}

I have tried online compilers tool, and they do not accept the

test(false);

line, which sounds to me what the normal behavior should be.

In addition, this behavior can cause issues with overloaded methods. i.e., you have a test(bool* pb) method and an overloaded version with a pointer: test(int* pv)

bool test(bool* pb)
{
    if (NULL != pb)
        return *pb;
    else
        return false;
}

bool test(int* pb)
{
    if (NULL != pb)
        return true;
    else
        return false;
}

void main()
{
    test(false); // won't compile anymore: error C2668: 'test' : ambiguous call to overloaded function
    test(true); // won't compile: error C2664: 'test' : cannot convert parameter 1 from 'bool' to 'bool *'
}

BTW I'm also using VS2012, which has the same behavior with the same test codes.


MSVC treats the expression false as a null pointer constant.

A null pointer constant can be implicitly converted to any pointer type, resulting in a null pointer value.

The correct behavior according to the standard is to treat only integer literals with value 0 as null pointer constants. Although it has value 0, false is not an integer literal.

However this rule is only in place since resolution of CWG issue 903. Before that every integral constant expression with value 0 was a null pointer constant.

MSVC is not implementing the defect report with default flags and still follows this old rule, according to which the expression false is a null pointer constant.

If you give MSVC the flag /permissive- to make it behave more standard-conform and implement the new rule. With /std:c++20 or higher this is also set by default, if I am not mistaken.

Note however, that you still have this problem if you use a literal 0 in your code and yes, it can affect overload resolution.

Values other than 0, even if an integer literal, are never null pointer constants and therefore cannot be converted to pointers implicitly. This also applies to true which has value 1. Therefore overload resolution may be affected by the specific value passed as argument.

Null pointer constants are what makes NULL work to initialize and compare null pointers, by having NULL expand either to an integer literal with value 0 or to nullptr. The latter is, since C++11, an alternative null pointer constant.