Disabling pointer output in C++ streams?

2019-06-16 18:40发布

问题:

If you hand any pointer to a C++ stream, it's address will be put into the output. (Obviously unless there's a more specific output handler.)

void* px = NULL;
const char* ps = "Test";
FooType* pf = ...;
stringstream s;
s << ps << " " << px << " " << pf "\n";
s.str(); // yields, for example: "Test 0 AF120089"

This can be a problem, if the user erroneously was trying to actually print the value of FooType.

And it is also a problem when mixing wide char and narrow char, because instead of a compiler error, you'll get the address printed:

const wchar_t* str = L"Test! (Wide)";
// ...
cout << str << "\n"; // Ooops! Prints address of str.

So I was wondering - since I very rarely want to output a pointer value, would it be possible to disable formatting of pointer values, so that inserting a pointer value into a stream would result in a compiler error? (Outputting of pointer values could then be easily achieved by using a wrapper type or casting the pointer values to size_t or somesuch.)

Edit: In light of Neil's answer (disabling void* output by providing my own void* output operator) I would like to add that it would be nice if this also worked for tools such as Boost.Format, that make implicit use of the output operator defined in the std namespace ...

回答1:

This gives a compilation error in g++ if the second and/or third output to cout is uncommented:

#include <iostream>
using namespace std;

ostream & operator << ( const ostream &, void * ) {
}


int main() {
    int n = 0;
    cout << 0;
//  cout << &n;
//  cout << (void *) 0;
}


回答2:

A global template version of operator<< seems to work:

#include <iostream>
#include <boost/static_assert.hpp>

template<typename T>
std::ostream & operator<<(std::ostream & stream, T* value) {
    BOOST_STATIC_ASSERT(false);
}

int main() {
    int foo = 5;
    int * bar = &foo;

    std::cout << bar << std::endl;
}

Edit: This solution does not work as intended, as the template also captures string literals. You should prefer @Neil's solution.



回答3:

Yes, you can cause a compilation error by providing your own overload of ostream's operator <<.

#include <iostream>

template <typename T>
std::ostream& operator << (std::ostream& s, T* p)
{
  char ASSERT_FAILED_CANNOT_OUTPUT_POINTER[sizeof(p) - sizeof(p)];
}

int main()
{
   int x;
   int* p = &x;
   cout << p;
}


回答4:

Keep the operator << unimplemented for pointers.

template<typename T>
std::ostream& operator<<(std::ostream &stream, T* value);

Edit: Or better to put an invalid typename to get compiler error.



标签: c++ iostream