Notas importantes dos comentários abaixo:
Por Martin:
@Chareles: Então, por esse requisito, todos os manipuladores são pegajosos. Exceto setw, que parece ser redefinido após o uso.
Por Charles:
Exatamente! e o único motivo pelo qual o setw parece se comportar de maneira diferente é porque existem requisitos nas operações de saída formatadas para explicitamente .width (0) o fluxo de saída.
A seguir, é apresentada a discussão que leva à conclusão acima:
Observando o código, os seguintes manipuladores retornam um objeto em vez de um fluxo:
setiosflags
resetiosflags
setbase
setfill
setprecision
setw
Essa é uma técnica comum para aplicar uma operação apenas ao próximo objeto aplicado ao fluxo. Infelizmente, isso não os impede de serem pegajosos. Os testes indicam que todos eles, exceto setw
são pegajosos.
setiosflags: Sticky
resetiosflags:Sticky
setbase: Sticky
setfill: Sticky
setprecision: Sticky
Todos os outros manipuladores retornam um objeto de fluxo. Portanto, qualquer informação de estado alterada deve ser registrada no objeto de fluxo e, portanto, permanente (até que outro manipulador altere o estado). Assim, os seguintes manipuladores devem ser manipuladores pegajosos .
[no]boolalpha
[no]showbase
[no]showpoint
[no]showpos
[no]skipws
[no]unitbuf
[no]uppercase
dec/ hex/ oct
fixed/ scientific
internal/ left/ right
Esses manipuladores realmente executam uma operação no próprio fluxo, e não no objeto do fluxo (embora tecnicamente o fluxo faça parte do estado dos objetos do fluxo). Mas não acredito que eles afetem qualquer outra parte do estado dos objetos de fluxo.
ws/ endl/ ends/ flush
A conclusão é que o setw parece ser o único manipulador da minha versão que não é pegajoso.
Para Charles, um truque simples para afetar apenas o próximo item da cadeia:
Aqui está um exemplo de como um objeto pode ser usado para alterar temporariamente o estado e depois devolvê-lo pelo uso de um objeto:
#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