6

I learned about std::nullptr_t that is the type of the null pointer literal, nullptr.

Then I made small program :

#include <iostream>

int main() 
{
    std::nullptr_t n1; 
    std::cout<<n1<<endl;
    return 0;
} 

Here, nullptr_t is data type and n1 is variable and I'm trying to print the value of variable. But, Compiler give an error:

prog.cpp: In function 'int main()':
prog.cpp:6:11: error: ambiguous overload for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'std::nullptr_t')
  std::cout<<n1<<endl;

Why does not std::nullptr_t work with std::cout in C++? What am I wrong here?

  • 4
    Just a guess, but since `std::nullptr_t` is the type of the null pointer literal `nullptr`, the value of `n1` is `nullptr`. So you're trying to output `nullptr` but `operator<<` is overloaded for several types of pointers, so the compiler doesn't know how to choose. – rhobincu Sep 16 '17 at 17:43
  • Besides, what did you expect to happen? – rhobincu Sep 16 '17 at 17:49
  • @rhobincu If I write `int i`; and `cout< –  Sep 16 '17 at 17:52
  • 1
    `void f(long); void f(short);` Calling `f(0);` would also be ambiguous. Same reason here. – Rakete1111 Sep 16 '17 at 17:54
  • If you try and output an integer variable, the program will print the value of that variable. What do you expect to see when you print a nullptr_t variable? – rhobincu Sep 16 '17 at 17:54
  • @rhobincu I think print 0. –  Sep 16 '17 at 17:56
  • Following @rhobincu you can cast the n1 to a pointer type or integral type to output it. – snow_abstraction Sep 16 '17 at 17:56
  • But a nullptr_t variable can't hold an integer value, so it can't be 0. – rhobincu Sep 16 '17 at 17:57
  • More importantly, which actual problem needs addresses written to `std::cout`? I don't think we're helping you as much as we can if we merely consider this question the iceberg rather than the tip of the iceberg. You shouldn't want to or need to write addresses to `std::cout` any more than you should want to or need to read addresses from `std::cin`. – autistic Sep 17 '17 at 00:54

1 Answers1

10

operator<< for output streams has overloads for multiple different types of pointers, but not std::nullptr_t 1. This means that the compiler cannot determine which overload to call, because any of the overloads accepting a pointer are equally good. (For example, it accepts char const * for C-style strings, and also void const *, which will output the raw pointer value.)

One option to fix this would be to define your own overload that forces the use of the void const * overload:

std::ostream & operator<<(std::ostream &s, std::nullptr_t) {
    return s << static_cast<void *>(nullptr);
}

Or have it do something else:

std::ostream & operator<<(std::ostream &s, std::nullptr_t) {
    return s << "nullptr";
}

Notes:

  • 1 As pointed out in the comments, there is an overload accepting std::nullptr_t in C++17, so this will cease to be an issue if you are using a conforming C++17 implementation.
  • endl needs std::-qualification -- but you should use '\n' here anyway. (std::endl is only a good idea when you need the stream flushed.)
cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • 4
    Note that this issue got resolved in C++17: http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt However, none of the compilers I tried seems to support it yet. – Jodocus Sep 16 '17 at 17:56
  • 1
    @Jodocus It's not a compiler issue, but a library one. libstdc++ and libc++ both don't implement it, yes. – Rakete1111 Sep 16 '17 at 18:04
  • 2
    overloading an operator outside of a type's namespace is bad, and in std is illegal. – Yakk - Adam Nevraumont Sep 16 '17 at 18:18
  • @Yakk can you elaborate? – Fureeish Sep 16 '17 at 18:20
  • 2
    @fureeeish Overloading an operator of importance and distinction, outside or not in, the namespace in which a type (not to typecast) is defined, is a less than ideal (one could say bad) idea, due to ADL failure, while defining overloads within the namespace std is ill advised as it renders your program as formed as the action is advised. Thus we fall upon the saying, one is damned if one does, so don't do it. Had the type a template parameter from outside std, then your woes would be washed on the tide of no more troubles. (That is as elaborate as I can write given character limit) – Yakk - Adam Nevraumont Sep 16 '17 at 21:23
  • According to the standard (section 20.5.4.2.1 [namespace.std]): "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." So, adding an overload for `nullptr_t` is not permitted according to the standard. That being said, most compilers still let you get away with it, but just know that it could break at any time for any reason. – callyalater Apr 03 '18 at 17:16
  • @callyalater Can't the operator be added to your program's namespace? I forget the visibility rules for free operators, but I thought the compiler will search the namespaces for the argument types as well as the namespaces you can access without explicit scope resolution. – cdhowie Apr 03 '18 at 23:28
  • Only if one of the inputs to the stream is a user defined type outside of the `std` namespace (for it to be legal). That said, most compilers will still let you do it because it is easier that way. – callyalater Apr 04 '18 at 14:36
  • Just met it myself… turns out that it works on `clang` (C++17 mode), but fails on `gcc` (C++17 mode as well). – val - disappointed in SE Jun 14 '19 at 09:40