11

I read about std::is_pointer in C++.

Then I wrote the program and check whether T is a pointer type or not using std::is_pointer.

#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??
}

Output : [Wandbox Demo]

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

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

5 Answers 5

21

Because std::nullptr_t is not a pointer type. And is_pointer only evaluates to true for pointer types.

nullptr_t is convertible to a pointer, but it isn't a pointer. Indeed, nullptr_t is not a class type, integral, floating-point, enumerator, or any kind of type other than is_null_pointer type. It has its own unique classification in the categorization of types.

Sign up to request clarification or add additional context in comments.

6 Comments

Any Idea about the rational behind that design decision?
@MikeMB Yeah, so it is not accidentally deduced as anything else in template overload resolution. having int 0 being a null pointer content was a mess
nullptr_t is not a class type? Is that explicitly mandated? [lex.nullptr] only states that it is not a pointer type.
@MikeMB: The problem with that would be that template <typename T> void f(T*); f(nullptr) would then be valid. Currently, if you want to allow that call, you must add an overload void f(std::nullptr_t) but that overload can forward to e.g. f<void*>. However, if nullptr was a pointer type and you did not want it, removing it from the oveload set would be more complicated.
@Quentin: "Is that explicitly mandated?" Yes. It is listed in [basic.fundamental], so it cannot be a class type. And is_null_pointer is a primary type category; for any type T, only one of the primary category traits will be true.
|
10

Because it's not a pointer type. It's a distinct type that is implicitly convertible to any pointer type.

As the note in [lex.nullptr] summarizes:

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 ]

Comments

6

As unintuitive as it sounds, std::nullptr_t is not a pointer type. For instance, you cannot dereference a std::nullptr_t, so it'd be pretty weird if is_pointer_type<nullptr_t>::value was true.

It is merely convertible to any pointer type.

2 Comments

it not being dereferenceable its the first argument I've heard that actually makes sense and carries a real weight.
@bolov, zneak: You can't dereference a void * either though.
4

Because std::nullptr_t is not a pointer type itself, but the type of the null pointer literal 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.

From the standard, 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].

Comments

1

It's definitely unintuitive in some cases, but it makes sense:

  1. Value-wise, it doesn't behave like a pointer; it cannot point to anything.
    For example, you cannot do

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

    and expect to get a pointer to the same address that p points to.

  2. Type-wise, it doesn't behave like a pointer. For example,

    std::is_pointer<P>::value
    

    should imply

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

    but that clearly isn't the case.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.