Ghi chú quan trọng từ các ý kiến dưới đây:
Bởi Martin:
@Charele: Sau đó, theo yêu cầu này, tất cả các thao tác đều dính. Ngoại trừ setw mà dường như được thiết lập lại sau khi sử dụng.
Charles:
Chính xác! và lý do duy nhất mà setw dường như hành xử khác đi là bởi vì có các yêu cầu đối với các hoạt động đầu ra được định dạng để rõ ràng. Băng thông (0) luồng đầu ra.
Sau đây là cuộc thảo luận dẫn đến kết luận trên:
Nhìn vào mã, các trình điều khiển sau đây trả về một đối tượng chứ không phải là một luồng:
setiosflags
resetiosflags
setbase
setfill
setprecision
setw
Đây là một kỹ thuật phổ biến để áp dụng một thao tác cho chỉ đối tượng tiếp theo được áp dụng cho luồng. Thật không may, điều này không ngăn cản họ bị dính. Các xét nghiệm chỉ ra rằng tất cả chúng ngoại trừ setw
là dính.
setiosflags: Sticky
resetiosflags:Sticky
setbase: Sticky
setfill: Sticky
setprecision: Sticky
Tất cả các thao tác khác trả về một đối tượng luồng. Do đó, bất kỳ thông tin trạng thái nào chúng thay đổi phải được ghi lại trong đối tượng luồng và do đó là vĩnh viễn (cho đến khi một trình thao tác khác thay đổi trạng thái). Do đó, các trình thao tác sau phải là Trình thao tác dính .
[no]boolalpha
[no]showbase
[no]showpoint
[no]showpos
[no]skipws
[no]unitbuf
[no]uppercase
dec/ hex/ oct
fixed/ scientific
internal/ left/ right
Các trình điều khiển này thực sự thực hiện một thao tác trên chính luồng chứ không phải đối tượng luồng (Mặc dù về mặt kỹ thuật, luồng là một phần của trạng thái đối tượng luồng). Nhưng tôi không tin rằng chúng ảnh hưởng đến bất kỳ phần nào khác của trạng thái đối tượng luồng.
ws/ endl/ ends/ flush
Kết luận là setw dường như là trình thao tác duy nhất trên phiên bản của tôi không dính.
Đối với Charles, một mẹo đơn giản chỉ ảnh hưởng đến mục tiếp theo trong chuỗi:
Dưới đây là một ví dụ về cách một đối tượng có thể được sử dụng để thay đổi trạng thái sau đó thay đổi trạng thái sau đó đưa nó trở lại bằng cách sử dụng một đối tượng:
#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