Почему нет необходимости специализироваться на `std::nullptr_t`, если есть специализированная функция И шаблонная функция
Рассмотрим следующий код:
#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
}
Я удивлен, что g++ 7.2.0
не выдает ошибку о неоднозначном разрешении перегрузки, как мне кажется nullptr
а также NULL
может вписаться в любой тип указателя, в том числе fun(int*)
специализированный из шаблона, при условии, что нет перегрузки, специализированной для std::nullptr_t
,
Почему fun(nullptr)
а также fun(NULL)
решает непосредственно fun(const char *)
?
1 ответ
std::nullptr_t
не указатель, поэтому он не будет соответствовать шаблону T*
в шаблоне вашей функции.
Как бы нелогично это ни было, следующее утверждение не сработает:
static_assert(std::is_pointer<std::nullptr_t>() == false);
Что касается NULL
, это определенный макросом реализации. Если верить cppreference, это либо целочисленный литерал со значением ноль (поэтому не указатель), либо значение типа std::nullptr_t
, что объясняется выше. Это не void*
указатель.