I was reading Effective Modern C++ by S. Meyers, and I found something I can't quite wrap my head around.
Item 8 explains why nullptr
should be preferred over 0
or NULL
. The main argument in favor of nullptr
is a safer behavior in overload resolutions. In practice you avoid unintended mixups between pointers and integer types, but this is not the point of my question.
To get to my actual question, consider the code below, which is based on the example used in the book:
#include <memory>
class MyClass {
int a;
};
// dummy functions that take pointer types
int f1(std::shared_ptr<MyClass> spw){return 1;};
double f2(std::unique_ptr<MyClass> upw){return 1.0;};
bool f3(MyClass* pw){return true;};
// template that calls a function with a pointer argument
template<typename FuncType,
typename PtrType>
auto CallFun(FuncType func, PtrType ptr) -> decltype(func(ptr))
{
return func(ptr);
}
int main()
{
// passing null ptr in three different ways
// they all work fine int this case
auto result1 = f1(0); // pass 0 as null ptr to f1
auto result2 = f2(NULL); // pass NULL as null ptr to f2
auto result3 = f3(nullptr); // pass nullptr as null ptr to f3 }
// passing null ptr in three different ways through the template
// only nullptr works in this case
auto result4 = CallFun(f1, 0); // compile error!
auto result5 = CallFun(f2, NULL); // compile error!
auto result6 = CallFun(f3, nullptr); // OK
return 0;
}
The first three direct calls to f1
, f2
and f3
compile fine for either 0
, NULL
, or nullptr
as a null pointer. The subsequent 3 calls, which are performed through the templates function CallFun
are much more picky: you have to use nullptr
, or no conversion between integer types (0
and NULL
) will be accepted. In other words type checking seems to be more strict when it occurs inside the template. Can somebody clarify what is going on?
CallFun
deduces the type of PtrType
for 0
and NULL
as int
, which don't implicitly convert to a pointer type.
If you want to see what I mean, just try storing 0
and NULL
in an auto
'd variable first, and calling f1
an f2
from those variables. They won't compile.
0
and NULL
themselves implicitly cast to a pointer type because they're literal values I guess. There's probably something about it in the standard but I think you get the point.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With