कौन-से Iomanip मैनिपुलेटर 'चिपचिपे' हैं?


140

मुझे हाल ही में stringstreamइस तथ्य के कारण एक समस्या पैदा हो गई थी कि मैंने गलत तरीके से मान लिया था कि मैं std::setw()हर प्रविष्टि के लिए स्ट्रिंग को प्रभावित करूंगा, जब तक कि मैं स्पष्ट रूप से नहीं बदल जाता। हालांकि, यह सम्मिलन के बाद हमेशा परेशान होता है।

// With timestruct with value of 'Oct 7 9:04 AM'
std::stringstream ss;
ss.fill('0'); ss.setf(ios::right, ios::adjustfield);
ss << setw(2) << timestruct.tm_mday;
ss << timestruct.tm_hour;
ss << timestruct.tm_min;
std::string filingTime = ss.str(); // BAD: '0794'

इसलिए, मेरे पास कई प्रश्न हैं:

  • ऐसा क्यों है setw()?
  • किसी भी अन्य जोड़तोड़ इस तरह हैं?
  • क्या व्यवहार std::ios_base::width()और के बीच अंतर है std::setw()?
  • अंत में एक ऑनलाइन संदर्भ है जो स्पष्ट रूप से इस व्यवहार का दस्तावेज है? मेरा विक्रेता प्रलेखन (MS Visual Studio 2005) स्पष्ट रूप से यह दिखाने के लिए प्रतीत नहीं होता है।

जवाबों:


87

नीचे टिप्पणी से महत्वपूर्ण नोट:

मार्टिन द्वारा:

@ चक्र: फिर इस आवश्यकता के द्वारा सभी जोड़तोड़ चिपचिपे होते हैं। सेट के अलावा जो उपयोग के बाद रीसेट होने लगता है।

चार्ल्स द्वारा:

बिल्कुल सही! और एकमात्र कारण जो सेट किया गया है वह अलग-अलग व्यवहार करता प्रतीत होता है क्योंकि आउटपुट स्ट्रीम को स्पष्ट करने के लिए स्वरूपित आउटपुट ऑपरेशन (0) आउटपुट स्ट्रीम पर आवश्यकताएं हैं।

निम्नलिखित चर्चा है जो उपरोक्त निष्कर्ष पर ले जाती है:


कोड को देखते हुए निम्नलिखित जोड़तोड़ एक धारा के बजाय एक वस्तु लौटाते हैं:

setiosflags
resetiosflags
setbase
setfill
setprecision
setw

यह एक सामान्य तकनीक है जो केवल अगली वस्तु पर एक ऑपरेशन को लागू करने के लिए है जो धारा पर लागू होती है। दुर्भाग्य से यह उन्हें चिपचिपा होने से रोकता नहीं है। टेस्ट से संकेत मिलता है कि उनमें से सभी setwचिपचिपे हैं।

setiosflags:  Sticky
resetiosflags:Sticky
setbase:      Sticky
setfill:      Sticky
setprecision: Sticky

अन्य सभी जोड़तोड़ एक स्ट्रीम ऑब्जेक्ट वापस करते हैं। इस प्रकार किसी भी राज्य सूचना को वे स्ट्रीम ऑब्जेक्ट में दर्ज किया जाना चाहिए और इस प्रकार स्थायी है (जब तक कि कोई अन्य जोड़तोड़ राज्य नहीं बदलता है)। इस प्रकार निम्नलिखित जोड़तोड़ चिपचिपा जोड़तोड़ होना चाहिए ।

[no]boolalpha
[no]showbase
[no]showpoint
[no]showpos
[no]skipws
[no]unitbuf
[no]uppercase

dec/ hex/ oct

fixed/ scientific

internal/ left/ right

ये जोड़तोड़ वास्तव में स्ट्रीम ऑब्जेक्ट के बजाय स्ट्रीम पर ही एक ऑपरेशन करते हैं (हालांकि तकनीकी रूप से स्ट्रीम स्ट्रीम ऑब्जेक्ट्स स्टेट का हिस्सा है)। लेकिन मुझे विश्वास नहीं है कि वे धारा वस्तुओं राज्य के किसी अन्य हिस्से को प्रभावित करते हैं।

ws/ endl/ ends/ flush

निष्कर्ष यह है कि सेटव्यू मेरे संस्करण पर एकमात्र मैनिपुलेटर लगता है जो चिपचिपा नहीं है।

चार्ल्स के लिए श्रृंखला में केवल अगले आइटम को प्रभावित करने की एक सरल चाल है:
यहां एक उदाहरण है कि कैसे एक वस्तु का उपयोग अस्थायी रूप से राज्य को बदलने के लिए किया जा सकता है, फिर इसे किसी वस्तु के उपयोग से वापस रखा जा सकता है:

#include <iostream>
#include <iomanip>

// Private object constructed by the format object PutSquareBracket
struct SquareBracktAroundNextItem
{
    SquareBracktAroundNextItem(std::ostream& str)
        :m_str(str)
    {}
    std::ostream& m_str;
};

// New Format Object
struct PutSquareBracket
{};

// Format object passed to stream.
// All it does is return an object that can maintain state away from the
// stream object (so that it is not STICKY)
SquareBracktAroundNextItem operator<<(std::ostream& str,PutSquareBracket const& data)
{
    return SquareBracktAroundNextItem(str);
}

// The Non Sticky formatting.
// Here we temporariy set formating to fixed with a precision of 10.
// After the next value is printed we return the stream to the original state
// Then return the stream for normal processing.
template<typename T>
std::ostream& operator<<(SquareBracktAroundNextItem const& bracket,T const& data)
{
    std::ios_base::fmtflags flags               = bracket.m_str.flags();
    std::streamsize         currentPrecision    = bracket.m_str.precision();

    bracket.m_str << '[' << std::fixed << std::setprecision(10) << data << std::setprecision(currentPrecision) << ']';

    bracket.m_str.flags(flags);

    return bracket.m_str;
}


int main()
{

    std::cout << 5.34 << "\n"                        // Before 
              << PutSquareBracket() << 5.34 << "\n"  // Temp change settings.
              << 5.34 << "\n";                       // After
}


> ./a.out 
5.34
[5.3400000000]
5.34

अच्छा धोखा चादर। जानकारी कहां से आई है, इसका संदर्भ जोड़ें और यह एक सही उत्तर होगा।
मार्क रैनसम

1
हालाँकि मैं उस सेटफिल को सत्यापित कर सकता हूं () वास्तव में 'चिपचिपा' है, हालांकि यह एक वस्तु देता है। इसलिए मुझे लगता है कि यह उत्तर सही नहीं है।
जॉन के

2
एक धारा को लौटाने वाली वस्तुओं को चिपचिपा होना चाहिए, जबकि जो एक वस्तु वापस करते हैं वह चिपचिपा हो सकता है लेकिन इसकी आवश्यकता नहीं है। मैं जॉन की जानकारी के साथ उत्तर को अपडेट करूंगा।
मार्टिन यॉर्क

1
मुझे यकीन नहीं है कि मैं आपके तर्क को समझता हूं। पैरामीटर लेने वाले सभी जोड़तोड़ को एक अनिर्दिष्ट वस्तु को लौटाने वाले स्वतंत्र कार्यों के रूप में कार्यान्वित किया जाता है जो एक धारा पर कार्य करता है जब उस वस्तु को धारा में डाला जाता है क्योंकि यह मापदंडों के साथ सम्मिलन सिंटैक्स को संरक्षित करने का एकमात्र (?) तरीका है। किसी भी तरह से, operator<<मैनिपुलेटर के लिए उपयुक्त यह सुनिश्चित करता है कि धारा की स्थिति को एक निश्चित तरीके से बदल दिया जाए। किसी भी प्रकार के राज्य के संतरी के लिए न तो फॉर्म सेट होता है। यह केवल अगले स्वरूपित सम्मिलन ऑपरेशन का व्यवहार है जो निर्धारित करता है कि यदि कोई है तो राज्य का कौन सा हिस्सा रीसेट है।
सीबी बेली

3
बिल्कुल सही! और एकमात्र कारण जो setwअलग-अलग व्यवहार करता प्रतीत होता है क्योंकि स्पष्ट रूप .width(0)से आउटपुट स्ट्रीम के लिए स्वरूपित आउटपुट ऑपरेशन पर आवश्यकताएं हैं ।
सीबी बेली

31

जो कारण width'चिपचिपा' प्रतीत नहीं होता है, वह यह है कि कुछ प्रचालनों को .width(0)आउटपुट स्ट्रीम पर कॉल करने की गारंटी दी जाती है। वो है:

21.3.7.9 [lib.string.io]:

template<class charT, class traits, class Allocator>
  basic_ostream<charT, traits>&
    operator<<(basic_ostream<charT, traits>& os,
               const basic_string<charT,traits,Allocator>& str);

22.2.2.2.2 [lib.facet.num.put.virtuals]: टेम्प्लेट के do_putलिए सभी अतिभार num_put। इन के भार के द्वारा किया जाता है operator<<एक लेने basic_ostreamऔर एक संख्यात्मक प्रकार में बनाया गया।

22.2.6.2.2 [lib.locale.money.put.virtuals]: टेम्प्लेट के do_putलिए सभी अतिभार money_put

२.६.२.५.४ [lib.ostream.inserters.character]: इन char प्रकारों की सरणियों के लिए बुनियादी_स्ट्रीम तात्कालिकता , या हस्ताक्षरित या संकेत के चार प्रकारों में से operator<<एक को लेने का अधिभार ।basic_ostreamcharcharunsigned char

सच कहूं तो मैं इसके लिए तर्क के बारे में निश्चित नहीं हूं, लेकिन ostreamस्वरूपित आउटपुट फ़ंक्शन द्वारा किसी भी अन्य राज्य को रीसेट नहीं किया जाना चाहिए। बेशक, आउटपुट ऑपरेशन में विफलता होने पर चीजें सेट की जा सकती हैं badbitऔर failbitहो सकती हैं, लेकिन यह उम्मीद की जानी चाहिए।

केवल यही कारण है कि मैं चौड़ाई को रीसेट करने के लिए सोच सकता हूं कि यह आश्चर्यचकित हो सकता है अगर, कुछ सीमांकित क्षेत्रों को आउटपुट करने की कोशिश करते समय, आपके सीमांकक गद्देदार थे।

उदाहरण के लिए

std::cout << std::setw(6) << 4.5 << '|' << 3.6 << '\n';

"   4.5     |   3.6      \n"

इसे 'सही' करने के लिए:

std::cout << std::setw(6) << 4.5 << std::setw(0) << '|' << std::setw(6) << 3.6 << std::setw(0) << '\n';

एक रीसेट चौड़ाई के साथ, वांछित आउटपुट को छोटे के साथ उत्पन्न किया जा सकता है:

std::cout << std::setw(6) << 4.5 << '|' << std::setw(6) << 3.6 << '\n';

6

setw()केवल अगले सम्मिलन को प्रभावित करता है। बस यही setw()व्यवहार है। का व्यवहार setw()जैसा है वैसा ही है ios_base::width()। मुझे मेरी setw()जानकारी cplusplus.com से मिली

आप यहां मैनिपुलेटर की पूरी सूची पा सकते हैं । उस लिंक से, सभी स्ट्रीम फ्लैग को तब तक सेट किया जाना चाहिए जब तक कि किसी अन्य मैनिपुलेटर द्वारा परिवर्तित न हो जाए। के बारे में एक टिप्पणी left, rightऔर internalmanipulators: वे अन्य झंडे की तरह कर रहे हैं और करते जारी रहती है जब तक बदल दिया है। हालांकि, उनका केवल एक प्रभाव होता है जब धारा की चौड़ाई निर्धारित की जाती है, और चौड़ाई को प्रत्येक पंक्ति में सेट किया जाना चाहिए। इसलिए, उदाहरण के लिए

cout.width(6);
cout << right << "a" << endl;
cout.width(6);
cout << "b" << endl;
cout.width(6);
cout << "c" << endl;

आपको देगा

>     a
>     b
>     c

परंतु

cout.width(6);
cout << right << "a" << endl;
cout << "b" << endl;
cout << "c" << endl;

आपको देगा

>     a
>b
>c

इनपुट और आउटपुट मैनिपुलेटर चिपचिपे नहीं होते हैं और केवल एक बार होते हैं जहां उनका उपयोग किया जाता है। पैराट्राइज्ड मैनिपुलेटर्स प्रत्येक अलग हैं, यहां प्रत्येक का संक्षिप्त विवरण दिया गया है:

setiosflagsआपको मैन्युअल रूप से झंडे सेट करने देता है, जिसकी एक सूची यहां फव्वारा हो सकती है , इसलिए यह चिपचिपा है।

resetiosflagssetiosflagsइसके समान व्यवहार करता है सिवाय इसके कि निर्दिष्ट झंडे को अनसुना कर दें।

setbase पूर्णांक के आधार को धारा में डाला जाता है (इसलिए आधार 16 में 17 "11" होगा, और आधार 2 में "10001") होगा।

setfillsetwउपयोग किए जाने पर स्ट्रीम में सम्मिलित करने के लिए भरण वर्ण सेट करता है।

setprecision फ़्लोटिंग पॉइंट मान सम्मिलित करते समय उपयोग की जाने वाली दशमलव परिशुद्धता सेट करता है।

setw निर्दिष्ट चरित्र के साथ भरकर केवल अगली प्रविष्टि को निर्दिष्ट चौड़ाई बनाता है setfill


खैर, उनमें से ज्यादातर सिर्फ झंडे स्थापित कर रहे हैं, इसलिए वे "चिपचिपा" हैं। setw () केवल एक सम्मिलन को प्रभावित करने वाला एकमात्र प्रतीत होता है। आप cplusplus.com/reference/iostream/manipulators में
डेविड ब्राउन

अच्छा std::hexभी चिपचिपा नहीं है और, जाहिर है, std::flushया std::setiosflagsचिपचिपा भी नहीं है। इसलिए मुझे नहीं लगता कि यह इतना आसान है।
sbi

बस हेक्स और सेटियोसफ़्लैग्स () का परीक्षण करते हुए, वे दोनों चिपचिपे लगते हैं (वे दोनों बस झंडे सेट करते हैं जो उस धारा के लिए जारी रहते हैं जब तक आप उन्हें बदलते नहीं हैं)।
डेविड ब्राउन

हाँ, वेब पेज जो std::hexचिपचिपा नहीं होने का दावा करता था, वह गलत था - मुझे यह पता चला। स्ट्रीम फ़्लैग, हालाँकि, यदि आप std::setiosflagsफिर से सम्मिलित नहीं करते हैं , तो भी परिवर्तित हो सकता है , इसलिए कोई इसे गैर-चिपचिपा के रूप में देख सकता है। इसके अलावा, std::wsचिपचिपा भी नहीं है। तो यह है नहीं है कि आसान।
sbi

आपने अपने उत्तर को बेहतर बनाने के लिए कुछ प्रयास किए हैं। +1
sbi
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.