Важные примечания из комментариев ниже:
Автор: Мартин:
@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>
struct SquareBracktAroundNextItem
{
SquareBracktAroundNextItem(std::ostream& str)
:m_str(str)
{}
std::ostream& m_str;
};
struct PutSquareBracket
{};
SquareBracktAroundNextItem operator<<(std::ostream& str,PutSquareBracket const& data)
{
return SquareBracktAroundNextItem(str);
}
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"
<< PutSquareBracket() << 5.34 << "\n"
<< 5.34 << "\n";
}
> ./a.out
5.34
[5.3400000000]
5.34