Search code examples
c++nulllanguage-lawyeroverload-resolutionnullptr

Why isn't it necessary to specialize for `std::nullptr_t` if there's a specialized function AND a templated function


Consider the following code:

#include <iostream>
using namespace std;

void fun(const char* s){
    if (s == nullptr) {
        puts("const char* nullptr");
    } else {
        printf("%s\n", s);
    }
}

template <typename T>
void fun(T* p){
    printf("%p\n", p);
}

int main() {
    int a;
    fun("abc"); // Resolves to fun(const char*)
    fun(&a); // Specializes the template to int*
    fun(nullptr); // Uses fun(const char*)??
    fun(NULL); // Same as above
}

I'm surprised that g++ 7.2.0 does not throw an error about ambiguous overload resolution, as I think nullptr and NULL could fit into any pointer type, including fun(int*) specialized from the template, provided there isn't an overload specialized for std::nullptr_t.

Why does fun(nullptr) and fun(NULL)resolves directly to fun(const char *)?


Solution

  • std::nullptr_t is not a pointer, so it will not pattern-match T* in your function template.

    As counter-intuitive as this is, the following assert will not fire:

    static_assert(std::is_pointer<std::nullptr_t>() == false);
    

    As for NULL, it is an implementation-defined macro. If cppreference is to be believed, it's either an integer literal with value of zero (so not a pointer), or a prvalue of type std::nullptr_t, which is explained above. It is not a void* pointer.