Важливі примітки із коментарів нижче:
Автор Мартіна:
@Chareles: Тоді за цією вимогою всі маніпулятори є липкими. За винятком setw, який, здається, буде скинутий після використання.
Чарльз:
Саме так! і єдиною причиною того, що setw поводиться по-різному, є те, що існують вимоги до форматованих вихідних операцій явно .width (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
Висновок полягає в тому, що setw, здається, є єдиним маніпулятором у моїй версії, який не є липким.
Для Чарльза простий трюк, що впливає лише на наступний елемент ланцюга:
Ось приклад того, як об’єкт можна тимчасово змінити стан, а потім повернути його за допомогою об’єкта:
#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