8

I was reading about nullptr and doing workout on g++ and also on VS2010.

When I did

#include <iostream>
using namespace std;

auto main(void)->int
{
    int j{};    
    int* q{};   

    cout << "Value of j: " << j << endl; // prints 0
    cout << nullptr << endl;
    cout << "Value of q: " << q << endl; // prints 0

    return 0;
}

printing the value of nullptr on screen, g++ and VS gave compiler error. Is it not allowed to print the value of nullptr on screen?

StackIT
  • 1,172
  • 2
  • 13
  • 25

3 Answers3

8

The pointer literal is the keyword nullptr. It is a prvalue of type std::nullptr_t.

Type nullptr_t should be convertible to T*, but compiler has no operator << for nullptr_t and don't know to which type you want to convert nullptr.

You can use this

cout << static_cast<void*>(nullptr) << endl;
ForEveR
  • 55,233
  • 2
  • 119
  • 133
  • nullptr is a literal, similar to true or false. We can print the value of true or false. Is there any standard which says, printing the nullptr will give compiler error? – StackIT Feb 14 '14 at 07:01
  • 1
    @StackIT `true` and `false` are of type `bool` and are therefore printable. `nullptr` is of type `std::nullptr_t` and is therefore not printable. – ApproachingDarknessFish Feb 14 '14 at 07:05
  • @StackIT It is implied by the fact that the standard does not provide a `<<` overload for `std::nullptr_t`, but for arbitrary pointer types (`T*`), combined with the fact that the conversion from `std::nullptr_t` to an arbitrary pointer type is ambiguous, as the particular `T` cannot be determined by the compiler. – Christian Rau Feb 14 '14 at 12:02
6

This is because nullptr is of type std::nullptr_t, which does not define the appropriate operators for std::cout to be able print objects of that type. You can define the operator yourself like this:

//std::cout is of type std::ostream, and nullptr is of type std::nullptr_t
std::ostream& operator << (std::ostream& os, std::nullptr_t ptr)
{
    return os << "nullptr"; //whatever you want nullptr to show up as in the console
}

After this function is defined, it will be used to handle all attempts to print nullptr via an ostream. This way you don't need to cast nullptr every time you print it.

ApproachingDarknessFish
  • 14,133
  • 7
  • 40
  • 79
  • I'm pretty sure adding your own ostream operator for standard types is not allowed (at least without putting the operator<< in another namespace). – Nevin Feb 14 '14 at 16:13
  • @Nevin Not allowed as in forbidden by the standard or not allowed as in frowned upon? – ApproachingDarknessFish Feb 14 '14 at 21:49
  • 1
    Forbidden by the standard: n3797 17.6.4.2.1 Namespace std [namespace.std] 1 The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. – Nevin Feb 14 '14 at 23:59
  • @Nevin In my example the operator was declared outside of any namespace. Is this acceptable? – ApproachingDarknessFish Feb 15 '14 at 00:03
  • @ApproachingDarknessFish Yes, I am 90% sure that is acceptable. I can't find the relevant section in the style guide right now, but I believe it is. – NHDaly Feb 24 '15 at 02:24
1

I ran into this problem while I was writing some type-parameterized test code (using templates). I needed to print a value of type T, where nullptr_t was a valid type for T. I came up with a solution where the value to be printed was wrapped inside a printable template function. This function then makes use of template specialization to provide the desired behavior when a nullptr_t is used.

#include <cstddef>
#include <iostream>

template <typename T> struct Printable
{
    Printable(const T& val) : val(val) {}
    void print(std::ostream& out) const {out << val;}
    const T& val;
};

template <> struct Printable<std::nullptr_t>
{
    Printable(nullptr_t) {}
    void print(std::ostream& out) const {out << "null";}
};

template <typename T>
Printable<T> printable(const T& value) {return Printable<T>(value);}

template <typename T>
std::ostream& operator<<(std::ostream& out, const Printable<T>& p)
{
    p.print(out);
    return out;
}

int main() {
    std::cout << printable(42) << " " << printable(nullptr) << "\n";
    return 0;
}

Ideone link

Emile Cormier
  • 28,391
  • 15
  • 94
  • 122