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

10

我在阅读有关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演示]

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

为什么 std::is_pointer<std::nullptr_t>::value 等于 false
5个回答

20
因为std::nullptr_t不是指针类型。而is_pointer只对指针类型求值得到truenullptr_t可转换为指针,但它并不是指针。事实上,nullptr_t既不是类类型,也不是整型、浮点型、枚举型或任何类型,除了is_null_pointer类型。它在类型分类中有其独特的分类。

3
你了解这个设计决定背后的理由吗? - MikeMB
2
@MikeMB 是的,这样就不会在模板重载解析中意外推导为其他内容。将int 0作为空指针内容是一团糟。 - M.M
nullptr_t 不是类类型?这是否明确规定?[lex.nullptr] 只说明它不是指针类型。 - Quentin
@M.M:我完全同意0的特殊语义非常棘手,但我本来想象/希望nullptr可以成为它自己的类型,但是那个类型将会是一个指针类型(就像void*是一个带有一些特殊语义的指针类型)。 - MikeMB
3
问题在于这会使得 template <typename T> void f(T*); f(nullptr) 成为有效调用。目前,如果你想允许这个调用,你必须添加一个重载void f(std::nullptr_t),但是这个重载可以转发到例如 f<void*>。然而,如果 nullptr 是一个指针类型并且你不想要它,从重载集中删除它会更加复杂。 - MSalters
3
@Quentin: "那是明确规定的吗?" 是的。它列在[basic.fundamental]中,因此它不能是类类型。而is_null_pointer是一个主类型类别;对于任何类型T,只有一个主类型类别特性将为true。 - Nicol Bolas

9
因为它不是指针类型。它是一种明确的类型,可以隐式转换为任何指针类型。
[lex.nullptr]中的注释总结所述:
指针文字是关键字nullptr。它是类型std::nullptr_t的prvalue。[注:std::nullptr_t是一个明确的类型,既不是指针类型也不是成员指针类型;相反,此类型的prvalue是空指针常量,并且可以转换为空指针值或空成员指针值。请参见[conv.ptr]和[conv.mem]。-注释结束]

6

听起来有些不直观,但std::nullptr_t并不是指针类型。例如,您不能引用std::nullptr_t,因此如果is_pointer_type<nullptr_t>::valuetrue,那将非常奇怪。

std::nullptr_t仅仅可以转换成任何指针类型。


3
这是我听到的第一个有意义且有实际分量的论点,因为它无法被解除引用。 - bolov
@bolov,zneak:你也不能解引用 void * - user541686

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

std::nullptr_t是空指针字面值nullptr的类型。它是一个独立的类型,既不是指针类型也不是成员指针类型。

从标准21.2.3 Null pointers [support.types.nullptr]中得知。

类型nullptr_­tnullptr表达式的类型的同义词,并具有[basic.fundamental]和[conv.ptr]中描述的特性。


1

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

从数值上看,它的行为不像指针;它不能“指向任何东西”。 例如,你不能这样做:
T *p = ...; reinterpret_cast<T *>(reinterpret_cast<std::nullptr_t>(p));
并期望得到一个指向与 p 指向相同地址的指针。
从类型上看,它的行为也不像指针。例如,
std::is_pointer<P>::value 应该意味着
std::is_same<P, std::remove_pointer<P>::type *>::value 但显然情况并非如此。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接