2009-01-01 8 views
28

Est-il possible de régler le manipulateur std::setw (ou sa fonction width) de façon permanente? Regardez ceci:"permanent" 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; 
} 

Après l'exécution, je vois:

001 2 4 8 10 20 40 80 100 

001 002 004 008 010 020 040 080 100 

à savoir chaque manipulateur tient sa place sauf le setw/width qui doit être réglé pour chaque entrée. Y at-il une manière élégante comment utiliser std::copy (ou autre chose) avec setw? Et par élégant je ne veux certainement pas créer son propre foncteur ou fonction pour écrire des choses dans std::cout.

Répondre

16

Eh bien, ce n'est pas possible. Aucun moyen de faire appel à nouveau .width à chaque fois. Mais vous pouvez utiliser boost, bien sûr:

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

Il ne créer son propre foncteur, mais il se passe derrière la scène :)

7

Depuis setw et width ne donnent pas lieu à un cadre persistant, un solution consiste à définir un type qui remplace operator<<, en appliquant setw avant la valeur. Cela permettrait à un ostream_iterator pour ce type de fonctionner avec std::copy comme ci-dessous.

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

On peut définir: (1) FixedWidthVal comme une classe de modèle avec les paramètres de type de données (typename) et la largeur (valeur), et (2) un operator<< pour un ostream et un FixedWidthVal qui applique setwpour chaque insertion.

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

Ensuite, il pourrait être appliqué avec std::copy (ou une boucle 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; 
} 

sortie (demo)

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

design vraiment agréable, que je pense serait applicable à beaucoup de situations. Ce serait idéal si la largeur pouvait être un paramètre d'exécution (plutôt que de compilation), bien que je ne puisse pas trouver un moyen agréable d'obtenir cette information dans "ostream_iterator". Vous pouvez également fournir une fonction de commodité 'template with_width (T v) {return FixedWidthVal (v, largeur); } 'pour éviter d'avoir à spécifier le type. –

+1

@j_random_hacker Bien, je devrais donner le crédit où le crédit est dû. J'ai adopté cette approche à partir de [une question codereview] (http://codereview.stackexchange.com/q/18291/35254), en ajoutant simplement le paramètre de modèle de type de données. Belle suggestion pour la fonction de commodité. – chappjc