কোন আইওমানিপ ম্যানিপুলেটরগুলি 'স্টিকি'?


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()?
  • অবশেষে এমন কোনও অনলাইন রেফারেন্স রয়েছে যা স্পষ্টভাবে এই আচরণটির নথিভুক্ত করে? আমার বিক্রেতার ডকুমেন্টেশন (এমএস ভিজ্যুয়াল স্টুডিও 2005) এটি পরিষ্কারভাবে দেখায় বলে মনে হয় না।

একটি কাজ বৃত্তাকার এখানে: stackoverflow.com/a/37495361/984471
মনোহর রেড্ডি Poreddy

উত্তর:


87

নীচের মন্তব্যগুলি থেকে গুরুত্বপূর্ণ নোটগুলি:

লিখেছেন মার্টিন:

@ চেরেলস: তারপরে এই প্রয়োজনীয়তার দ্বারা সমস্ত হেরফেরগুলি স্টিকি হয়। সেটউ ব্যতীত যা ব্যবহারের পরে পুনরায় সেট করা হবে বলে মনে হচ্ছে।

চার্লস দ্বারা:

একদম ঠিক! এবং সেটগুলি যে আলাদাভাবে আচরণ করবে বলে মনে হচ্ছে তার কারণ হ'ল সুস্পষ্টভাবে ফর্ম্যাট আউটপুট ক্রিয়াকলাপগুলির প্রয়োজনীয়তা রয়েছে w প্রস্থ (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
আমি নিশ্চিত নই যে আমি আপনার যুক্তি বুঝতে পেরেছি। পরামিতিগুলি গ্রহণকারী সমস্ত ম্যানিপুলেটরগুলি নির্ধারিত কোনও অবজেক্টকে ফিরিয়ে ফ্রি ফাংশন হিসাবে বাস্তবায়িত করা হয় যখন স্ট্রমে যখন সেই বস্তুটি স্রোতে sertedোকানো হয় তখন এটি পরামিতি সহ সন্নিবেশ বাক্য গঠন সংরক্ষণ করার একমাত্র (?) উপায়। যে কোনও উপায়ে, 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.virtual]: টেমপ্লেটের do_putজন্য সমস্ত ওভারলোড num_put। এগুলি সংখ্যার ধরণের operator<<একটি basic_ostreamও বিল্ট গ্রহণের ওভারলোড দ্বারা ব্যবহৃত হয় ।

22.2.6.2.2 [lib.locale.money.put.virtual]: টেমপ্লেটের do_putজন্য সমস্ত ওভারলোড money_put

27.6.2.5.4 [lib.ostream.inserters.character]: এর Overloads operator<<একটি গ্রহণ basic_ostreamএবং basic_ostream ইনস্ট্যান্স এর গৃহস্থালির কাজ টাইপ বা এক charসাইনড charবা unsigned 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()। আমি cplusplus.comsetw() থেকে আমার তথ্য পেয়েছি ।

আপনি এখানে ম্যানিপুলেটরগুলির একটি সম্পূর্ণ তালিকা পেতে পারেন । এই লিঙ্কটি থেকে, সমস্ত স্ট্রিম পতাকাগুলি অন্য ম্যানিপুলেটর দ্বারা পরিবর্তন না হওয়া অবধি সেট করে রাখা উচিত। সম্পর্কে এক নোট 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 প্রবাহে sertedোকানো পূর্ণসংখ্যার ভিত্তি সেট করে (সুতরাং 17 এর বেস 16 "11" হবে এবং বেস 2 তে "10001" হবে)।

setfillযখন setwব্যবহৃত হবে তখন স্ট্রিমটিতে সন্নিবেশ করানোর জন্য পূর্ণ চরিত্রটি সেট করে ।

setprecision ভাসমান পয়েন্ট মান সন্নিবেশ করার সময় ব্যবহৃত দশমিক নির্ভুলতা সেট করে।

setw বর্ণিত অক্ষরটি পূরণ করে কেবলমাত্র পরবর্তী সন্নিবেশ নির্দিষ্ট প্রস্থ তৈরি করে setfill


ভাল, তাদের বেশিরভাগই কেবল পতাকা স্থাপন করছেন, সুতরাং সেগুলি "স্টিকি"। সেটউ () কেবলমাত্র একমাত্র সন্নিবেশকে প্রভাবিত করে বলে মনে হচ্ছে। আপনি cplusplus.com/references/iostream/manipulators-
ডেভিড ব্রাউন

ভাল std::hexএছাড়াও চটচটে এবং স্পষ্টতই হয় না , std::flushবা std::setiosflagsহয় না স্টিকি না। সুতরাং আমি এটি এত সহজ বলে মনে করি না।
এসবিআই

কেবলমাত্র হেক্স এবং সেটিওসফ্ল্যাগগুলি পরীক্ষা করে (), তারা উভয়ই আঠালো বলে মনে হচ্ছে (তারা দু'টি কেবল ফ্ল্যাগ সেট করে যা আপনি সেগুলি পরিবর্তন না করা পর্যন্ত সেই স্ট্রিমের জন্য অব্যাহত থাকে)।
ডেভিড ব্রাউন 16

হ্যাঁ, ওয়েব পৃষ্ঠায় যে std::hexস্টিকি না বলে দাবি করেছিল তা ভুল ছিল - আমি এটিও খুঁজে পেয়েছি। স্ট্রিম ফ্ল্যাগগুলি অবশ্য আপনি std::setiosflagsআবার sertোকানো না হলেও পরিবর্তিত হতে পারে , যাতে কেউ এটিকে স্টিচিবিহীন হিসাবে দেখতে পারে। এছাড়াও, std::wsচটচটে নয়। সুতরাং এটি হল না যে সহজ।
এসবিআই

আপনার উত্তরটির উন্নতি করতে আপনি বেশ কিছু প্রচেষ্টা করেছেন। +1
এসবিআই
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.