2009-01-01 5 views
28

क्या कोई तरीका है std::setw मैनिपुलेटर (या उसके फ़ंक्शन width) को स्थायी रूप से सेट करने का कोई तरीका है? यह देखो:"स्थायी" 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; 
} 

चलाने के बाद, मैं देख रहा हूँ:

001 2 4 8 10 20 40 80 100 

001 002 004 008 010 020 040 080 100 

अर्थात प्रत्येक मैनिपुलेटर setw/width को छोड़कर अपनी जगह रखता है जिसे प्रत्येक प्रविष्टि के लिए सेट किया जाना चाहिए। क्या std::copy (या कुछ और) setw के साथ उपयोग करने का कोई शानदार तरीका है? और सुरुचिपूर्ण द्वारा मैं निश्चित रूप से std::cout में सामान लिखने के लिए अपने स्वयं के मज़ेदार या कार्य का निर्माण नहीं कर रहा हूं।

उत्तर

16

अच्छा, यह संभव नहीं है। इसे हर बार फिर से .width पर कॉल करने का कोई तरीका नहीं है।

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

यह अपनी ही functor पैदा नहीं करता है, लेकिन यह दृश्य :)

7
setw के बाद से

और width पीछे क्या होता है एक लगातार सेटिंग में परिणाम नहीं, एक: लेकिन आप निश्चित रूप से, को बढ़ावा देने का उपयोग कर सकते समाधान एक प्रकार को परिभाषित करना है जो operator<< को ओवरराइड करता है, मूल्य से पहले setw लागू करता है। यह के साथ काम करने के लिए उस प्रकार के लिए ostream_iterator की अनुमति देगा।

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

आप निर्धारित कर सकते हैं: (1) FixedWidthVal डेटा प्रकार के लिए मानकों (typename) और चौड़ाई (मान) के साथ एक टेम्पलेट वर्ग के रूप में, और (2) एक ostream के लिए एक operator<< और के लिए setwलागू होने वाला एक FixedWidthVal प्रत्येक प्रविष्टि

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

तो यह std::copy साथ लागू किया जा सकता है (या एक 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; 
} 

आउटपुट (demo)

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

सच अच्छा डिजाइन है, जो मुझे लगता है कि लागू किया जाएगा कई परिस्थितियों में। यह आदर्श होगा यदि चौड़ाई रनटाइम (संकलन-समय के बजाय) पैरामीटर हो सकती है, हालांकि मैं इस जानकारी को "ostream_iterator" में प्राप्त करने का एक अच्छा तरीका नहीं सोच सकता। आप सुविधा सुविधा 'टेम्पलेट <टाइपनाम टी, इंट डब्ल्यू> with_width (टी वी) {रिटर्न फिक्स्डविड्थवेल (वी, चौड़ाई) भी प्रदान कर सकते हैं; } 'प्रकार निर्दिष्ट करने के लिए सहेजने के लिए। –

+1

@j_random_hacker ठीक है, मुझे श्रेय देना चाहिए जहां क्रेडिट की देय है। मैंने इस दृष्टिकोण को [एक कोडरेव प्रश्न] (http://codereview.stackexchange.com/q/18291/35254) से अपनाया है, केवल डेटा प्रकार टेम्पलेट पैरामीटर जोड़ रहा है। सुविधा समारोह के लिए अच्छा सुझाव। – chappjc