C++98 allows using 0 or NULL to represent null pointers. If a pointer is expected and the compiler comes across 0 it interprets it as a null pointer. NULL is interpreted in the same manner. Some implementations map NULL to an int or long type. This led to a guideline on avoiding overloading functions on pointer and integral types, for example -
void f(int);
void f(bool);
void f(void*);
f(0); //calls f(int) and not f(void*)
f(NULL); //may not compile, if it does compile it will call f(int) and never f(void*)
C++11 introduces nullptr keyword whose type is std::nullptr_t. This type implicitly converts to all raw pointer types. Thus the call f(nullptr) will invoke f(void*) overload.
Template type deduction will not decue 0 and NULL to null pointers, it will deduce nullptr as a null pointer -
template<typename function, typename ptr>
decltype(auto) callFunction(function f, ptr p)
{
return f(p);
}
int f1(std::shared_ptr<std::string> p);
int f2(std::unique_ptr<std::string> p);
int f3(std::string * p);
auto r1 = callFunction(f1, 0); //Error
auto r2 = callFunction(f2, 0); //Error
auto r3 = callFunction(f3, nullptr); //Ok
The first call, involving f1 and 0, deduces 0 as int which can't be converted to std::shared_ptr<std::string>. The second call, involving f2 and NULL, deduces it as an integral type which can't be converted to std::unique_ptr<std::string>.
The third call, involving f3 and nulltpr, since nullptr allows conversion to std::string* it is Ok.
void f(int);
void f(bool);
void f(void*);
f(0); //calls f(int) and not f(void*)
f(NULL); //may not compile, if it does compile it will call f(int) and never f(void*)
C++11 introduces nullptr keyword whose type is std::nullptr_t. This type implicitly converts to all raw pointer types. Thus the call f(nullptr) will invoke f(void*) overload.
Template type deduction will not decue 0 and NULL to null pointers, it will deduce nullptr as a null pointer -
template<typename function, typename ptr>
decltype(auto) callFunction(function f, ptr p)
{
return f(p);
}
int f1(std::shared_ptr<std::string> p);
int f2(std::unique_ptr<std::string> p);
int f3(std::string * p);
auto r1 = callFunction(f1, 0); //Error
auto r2 = callFunction(f2, 0); //Error
auto r3 = callFunction(f3, nullptr); //Ok
The first call, involving f1 and 0, deduces 0 as int which can't be converted to std::shared_ptr<std::string>. The second call, involving f2 and NULL, deduces it as an integral type which can't be converted to std::unique_ptr<std::string>.
The third call, involving f3 and nulltpr, since nullptr allows conversion to std::string* it is Ok.