2011-05-23 8 views
8

Si pasa cualquier puntero a una secuencia C++, su dirección se colocará en la salida. (Obviamente, a menos que haya un gestor de salida más específico.)¿Desactivar la salida del puntero en flujos de C++?

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

Esto puede ser un problema, si el usuario erróneamente estaba tratando de imprimir realmente el valor de FooType.

Y también es un problema cuando se mezcla todo el carbón de leña y carbón estrecha, porque en lugar de un error de compilación, obtendrá la dirección impresa:

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

así que me preguntaba - ya que muy raramente quiero para generar un valor de puntero, ¿sería posible deshabilitar el formato de los valores del puntero, de modo que insertar un valor de puntero en una secuencia daría lugar a un error del compilador? (Salida de los valores del puntero podría entonces lograrse fácilmente mediante el uso de un tipo de envoltorio o lanzar los valores del puntero a size_t o algo por el estilo.)

Editar: A la luz de Neil's answer (incapacitante void * salida al proporcionar mi propia void * operador de salida) Me gustaría añadir que sería bueno si esto también funcionó para herramientas como Boost.Format, que hacen un uso implícito del operador de salida definido en el espacio de nombres std ...

Respuesta

3

Esto da un error de compilación en g ++ si la segunda y/o tercera salida en cout no está comentada:

#include <iostream> 
using namespace std; 

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


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

Hmmm ... esto se ve bien. El operador de salida void * "normal" se define en el espacio de nombres std, ¿no? Entonces, si hay un código que usa el de std, ¿esto no ayudará ...? –

+0

Algo funciona, pero formalmente no se permite sobrecargar operadores sin al menos un tipo de parámetro definido por el usuario. –

+1

@Bo ¿Y qué crees que es ostream? –

4

Una versión plantilla global de operator<< parece funcionar:

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

Editar: Esta solución no funciona según lo previsto, ya que la plantilla también captura literales de cadena. Deberías preferir la solución de @Neil.

+0

Genial, parece que se nos ocurrió casi la misma respuesta. – xDD

+0

¿No estaría esto restringido al código en el espacio de nombres global? Parece que el código en otros espacios de nombres encontraría ':: std :: operator <<' (debido a ADL en 'std :: cout') pero no' :: operator << ' – MSalters

+0

@MSalters: On [ideone it works] (http://ideone.com/MaqNp) incluso si la llamada proviene de otro espacio de nombres. Pero intuitivamente, hubiera estado de acuerdo contigo. –

1

Sí, puede causar un error de compilación al proporcionar su propia sobrecarga del operador < < de ostream.

#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; 
} 
+0

Como mencioné en una edición de mi propia respuesta, esto no funciona según lo previsto, porque también evita que imprima literales de cadenas. –

0

Mantenga el operator << sin aplicarse para los punteros.

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

Editar: O mejor poner un nombre de tipo no válido para conseguir error del compilador.

+0

Eso daría un error de enlazador, no uno de compilador, ¿no es así? –

+0

@Neil, correcto. Lo actualizaré. – iammilind

Cuestiones relacionadas