2009-01-01 10 views
28

¿Hay alguna manera de configurar el manipulador std::setw (o su función width) de forma permanente? Mira esto:"Permanente" std :: setw

#include <iostream> 
#include <iomanip> 
#include <algorithm> 
#include <iterator> 

int main(void) 
{ 
    int array[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256 }; 
    std::cout.fill('0'); 
    std::cout.flags(std::ios::hex); 
    std::cout.width(3); 

    std::copy(&array[0], &array[9], std::ostream_iterator<int>(std::cout, " ")); 

    std::cout << std::endl; 

    for(int i = 0; i < 9; i++) 
    { 
    std::cout.width(3); 
    std::cout << array[i] << " "; 
    } 
    std::cout << std::endl; 
} 

Después de carrera, veo:

001 2 4 8 10 20 40 80 100 

001 002 004 008 010 020 040 080 100 

es decir, cada manipulador ocupa su lugar excepto el setw/width que se debe configurar para cada entrada. ¿Hay alguna manera elegante de cómo usar std::copy (u otra cosa) junto con setw? Y por elegante, ciertamente no me refiero a crear funtores o funciones propios para escribir cosas en std::cout.

Respuesta

16

Bueno, no es posible. No hay forma de hacer que vuelva a llamar al .width. Pero se puede utilizar impulso, por supuesto:

#include <boost/function_output_iterator.hpp> 
#include <boost/lambda/lambda.hpp> 
#include <algorithm> 
#include <iostream> 
#include <iomanip> 

int main() { 
    using namespace boost::lambda; 
    int a[] = { 1, 2, 3, 4 }; 
    std::copy(a, a + 4, 
     boost::make_function_output_iterator( 
       var(std::cout) << std::setw(3) << _1) 
     ); 
} 

Se qué crear su propio funtor, pero sucede detrás de la escena :)

7

Desde setw y width no dan lugar a un entorno persistente, uno La solución es definir un tipo que anula operator<<, aplicando setw antes del valor. Esto permitiría que un ostream_iterator para ese tipo funcione con std::copy como se muestra a continuación.

int fieldWidth = 4; 
std::copy(v.begin(), v.end(), 
    std::ostream_iterator< FixedWidthVal<int,fieldWidth> >(std::cout, ",")); 

Se podía definir: (1) FixedWidthVal como una clase de plantilla con los parámetros de tipo de datos (typename) y anchura (valor), y (2) un operator<< para una ostream y una FixedWidthVal que se aplica setwpara cada inserción.

// FixedWidthVal.hpp 
#include <iomanip> 

template <typename T, int W> 
struct FixedWidthVal 
{ 
    FixedWidthVal(T v_) : v(v_) {} 
    T v; 
}; 

template <typename T, int W> 
std::ostream& operator<< (std::ostream& ostr, const FixedWidthVal<T,W> &fwv) 
{ 
    return ostr << std::setw(W) << fwv.v; 
} 

Entonces se podría aplicar con std::copy (o un bucle for):

// fixedWidthTest.cpp 
#include <iostream> 
#include <algorithm> 
#include <iterator> 
#include "FixedWidthVal.hpp" 

int main() { 
    // output array of values 
    int array[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256 }; 

    std::copy(array,array+sizeof(array)/sizeof(int), 
     std::ostream_iterator< FixedWidthVal<int,4> >(std::cout, ",")); 

    std::cout << std::endl; 

    // output values computed in loop 
    std::ostream_iterator<FixedWidthVal<int, 4> > osi(std::cout, ","); 
    for (int i=1; i<4097; i*=2) 
     osi = i; // * and ++ not necessary 

    std::cout << std::endl; 

    return 0; 
} 

salida (demo)

1, 2, 4, 8, 16, 32, 64, 128, 256, 
    1, 2, 4, 8, 16, 32, 64, 128, 256, 512,1024,2048,4096, 
+1

muy bonito diseño, que creo que sería aplicable a muchas situaciones Sería ideal si el ancho pudiera ser un parámetro de tiempo de ejecución (en lugar de tiempo de compilación), aunque no puedo pensar en una buena forma de obtener esta información "en" 'ostream_iterator'. También podría proporcionar una función de conveniencia 'template with_width (T v) {return FixedWidthVal (v, width); } 'para guardar tener que especificar el tipo. –

+1

@j_random_hacker Bueno, debería dar crédito donde se debe el crédito. Adopté este enfoque desde [una pregunta de revisión de código] (http://codereview.stackexchange.com/q/18291/35254), simplemente agregando el parámetro de plantilla de tipo de datos. Buena sugerencia para la función de conveniencia. – chappjc

Cuestiones relacionadas