2011-02-14 16 views
5

Existe la plantilla complex<> en la biblioteca estándar de C++, y tiene un operador < < sobrecargado para que emita números complejos en el formato (real_part, im_part). Necesito cambiar el comportamiento de ese operador para números complejos para que el formato de salida cambie a algo completamente diferente. Específicamente, necesito que la salida tenga el formato real_part\tim_part. ¿Cómo puedo hacer eso?Cambiar el formato de salida de número complejo

+1

¿A qué? ¡Realmente quiere truncar el número o quiere que se impriman 'peras!' Cada vez, debe especificar. – GManNickG

Respuesta

7

No hay forma directa de reemplazar operator <<, pero tiene algunas opciones. En primer lugar, usted podría escribir su propia función para imprimir números complejos:

template <typename T> void PrintComplex(const complex<T>& c) { 
    /* ... */ 
} 

Si desea seguir utilizando la sintaxis de flujo agradable, a continuación, un truco que podría hacer sería hacer una clase contenedora que envuelve un complex y luego define su propio operator << que lo imprime de una manera diferente. Por ejemplo:

template <typename T> class ComplexPrinter { 
public: 
    /* Conversion constructor allows for implicit conversions from 
    * complex<T> to ComplexPrinter<T>. 
    */ 
    ComplexPrinter(const complex<T>& value) : c(value) { 
     // Handled in initializer list 
    } 

    /* Output the complex in your own format. */ 
    friend ostream& operator<< (ostream& out, const ComplexPrinter& cp) { 
     /* ... print in your own format ... */ 
    } 

private: 
    complex<T> c; 
}; 

Una vez que tenga esto, se podía escribir algo como

cout << ComplexPrinter<double>(myComplex) << endl; 

Puede hacer esto aún más limpio escribiendo una función como esta para envolver el objeto para el que:

template <typename T> 
ComplexPrinter<T> wrap(const complex<T>& c) { 
    return ComplexPrinter<T>(c); 
} 

Esto entonces permite escribir

cout << wrap(myComplex) << endl; 

Lo cual no es perfecto, pero es bastante bueno.

Una cosa a tener en cuenta sobre el envoltorio anterior es que tiene un constructor de conversiones implícito configurado para permitirte convertir complex<T> a ComplexPrinter<T> s. Esto significa que si usted tiene un vector< complex<T> >, puede imprimirlo usando el código personalizado llamando

vector< complex<double> > v = /* ... */ 
copy (v.begin(), v.end(), ostream_iterator< ComplexPrinter<double> >(cout, " ")); 

En la salida, el constructor conversión implícita transformará sus complex<double> s en las envolturas, y el código personalizado hará el impresión para ti.

Si quieres ser muy aventurero y echar una cana al aire, incluso se podría escribir la clase de modo que solo almacena una referencia al original complex, como se muestra aquí:

template <typename T> class ComplexPrinter { 
public: 
    /* Conversion constructor allows for implicit conversions from 
    * complex<T> to ComplexPrinter<T>. 
    */ 
    ComplexPrinter(const complex<T>& value) : c(value) { 
     // Handled in initializer list 
    } 

    /* Output the complex in your own format. */ 
    friend ostream& operator<< (ostream& out, const ComplexPrinter& cp) { 
     /* ... print in your own format ... */ 
    } 

private: 
    const complex<T>& c; 
}; 

Esto elimina por completo cualquier copia y solo hace que el envoltorio sea una chapa delgada alrededor de un complex real. (Sin juego de palabras) Tendría que tener mucho cuidado si lo hace para no pasar estos objetos a través de los límites del alcance donde los objetos originales quedan fuera del alcance, pero si es lo que quiere, podría funcionar muy bien.

Espero que esto ayude!

+0

Gracias! ¡Eso es justo lo que necesitaba! – grzkv

3
template<class T> 
struct my_complex_format_type { 
    std::complex<T> const &x; 
    my_complex_format_type(std::complex<T> const &x) : x (x) {} 
    friend std::ostream& operator<<(std::ostream &out, 
            my_complex_format_type const &value) 
    { 
    out << "format value.x however you like"; 
    return out; 
    } 
}; 
template<class T> 
my_complex_format_type<T> my_complex_format(std::complex<T> const &x) { 
    return x; 
} 

void example() { 
    std::cout << my_complex_format(some_complex); 
} 
+0

No quiere decir que esta no sea una gran respuesta, pero ¿no es esto exactamente lo que publiqué hace unos minutos? :-) – templatetypedef

+0

@templatetypedef: Comencé a leer esta pregunta y luego escribí mi respuesta varios minutos antes de publicarla, y solo presioné "enviar" 67 segundos después de ti. ¿Es eso un problema? –

+0

@Fred Nurk- Mis disculpas, eso no fue para ser conflictivo. De hecho, me alegré de haber convergido en la misma respuesta ... ¡significa que este es probablemente un diseño realmente bueno! – templatetypedef

-1

No hay una manera realmente ordenada de hacerlo. Mi sugerencia sería deshacerme de iostreams y escribir algo más parecido a C en su lugar. Probablemente será más rápido de escribir, más rápido de leer y más rápido de ejecutar.

+0

+1: el formato de salida C++ huele mal. Recuerdo la introducción a las secuencias de IO en TC++ PL, donde Stroustrup comienza diciendo que no es fácil escribir una biblioteca que satisfaga a todos. Es más o menos como comenzar una broma diciendo que probablemente no a todos les gustará ... – 6502

+0

@ 6502: Estoy de acuerdo en que iostreams apestan, pero este caso de uso es en realidad ordenado. –

+0

-1, std :: complex es un ejemplo clásico donde el formato 'printf()' se rompe. – MSalters

1

Para cualquier instanciación específica de complex<T>, utilice un typedef fuerte (impulso tiene una versión) y emitido a ese tipo durante < < llamadas.Anule < < para ese tipo.

Si necesita anular < < para cualquier variación de complex<T>, entonces la vida será más difícil.