为什么 "std::is_pointer<std::nullptr_t>::value" 等于 false?

Why is "std::is_pointer<std::nullptr_t>::value" equal to false?

我在 C++ 中阅读了 std::is_pointer

然后我写了程序,用std::is_pointer检查T是否是指针类型。

#include <iostream>

int main() 
{
    std::cout<<std::boolalpha;
    std::cout<<"char : " <<std::is_pointer<char>::value<<std::endl; // OK
    std::cout<<"char * : "<<std::is_pointer<char *>::value<<std::endl; // OK
    std::cout<<"char ** : "<<std::is_pointer<char **>::value<<std::endl; // OK
    std::cout<<"char *** : "<<std::is_pointer<char ***>::value<<std::endl; // OK
    std::cout<<"std::nullptr_t : "<<std::is_pointer<std::nullptr_t>::value<<std::endl;  // Not ok, Why false??
}

输出 : [Wandbox Demo]

char : false
char * : true
char ** : true
char *** : true
std::nullptr_t : false

为什么 std::is_pointer<std::nullptr_t>::value 等于 false

因为std::nullptr_t本身不是指针类型,而是空指针字面量的类型nullptr.

std::nullptr_t is the type of the null pointer literal, nullptr. It is a distinct type that is not itself a pointer type or a pointer to member type.

根据标准,21.2.3 Null pointers [support.types.nullptr]

The type nullptr_­t is a synonym for the type of a nullptr expression, and it has the characteristics described in [basic.fundamental] and [conv.ptr].

因为不是指针类型。它是一种独特的类型,可以隐式转换为任何指针类型。

正如 [lex.nullptr] 中的注释总结的那样:

The pointer literal is the keyword nullptr. It is a prvalue of type std​::​nullptr_­t. [ Note: std​::​nullptr_­t is a distinct type that is neither a pointer type nor a pointer to member type; rather, a prvalue of this type is a null pointer constant and can be converted to a null pointer value or null member pointer value. See [conv.ptr] and [conv.mem].  — end note ]

因为std::nullptr_t不是指针类型is_pointer 仅对指针类型计算为 true

nullptr_t 可以转换为指针,但 不是 指针。实际上,nullptr_t 不是 class 类型、整数、浮点数、枚举数或 is_null_pointer 类型以外的任何类型。它在类型分类方面有自己独特的class化。

听起来不直观,std::nullptr_t 不是指针类型。例如,you cannot dereference a std::nullptr_t,所以如果 is_pointer_type<nullptr_t>::valuetrue 就很奇怪了。

它只能转换为任何指针类型。

在某些情况下肯定不直观,但有道理:

  1. Value-wise,它的行为不像一个指针;它不能指向任何东西
    例如,你不能做

    T *p = ...;
    reinterpret_cast<T *>(reinterpret_cast<std::nullptr_t>(p));
    

    并期望获得指向与 p 指向的同一地址的指针。

  2. Type-wise,它的行为不像指针。例如,

    std::is_pointer<P>::value
    

    应该暗示

    std::is_same<P, std::remove_pointer<P>::type *>::value
    

    但事实显然并非如此。