在 C++ 中重写 << 运算符时如何正确遵守 std::setw 和 std::fill
How to properly honor std::setw and std::fill when overriding << operator in C++
我有一个表示字符串的自定义数据类型:
struct ByteArray {
uint32_t len;
uint8_t* ptr;
}
并覆盖 << 运算符以将其输出到屏幕。
版本 1:
ostream &operator<<(ostream &os, const ByteArray &dt) {
os << string((const char*)dt.ptr,dt.len);
return os;
}
版本 2:
ostream &operator<<(ostream &os, const ByteArray &dt) {
os.write((const char *) dt.ptr, dt.len);
auto fill = os.width() - dt.len;
fill_n(std::ostream_iterator<char>(os), fill, os.fill());
return os;
}
我的输出代码类似于
ByteArray& value = ...; // a string of length 25
cout << '|' << left << setw(40) << value;
当我使用版本 1 时,它运行良好并显示:
|gAaNbDxVTyFjjhgGodAKyy9uk
但是版本 2 显示 17 个前导空白 spaces:
| gAaNbDxVTyFjjhgGodAKyy9uk
我想使用版本 2,因为它不会创建不必要的字符串对象。但是我如何正确处理 setw 和 fill 呢?
谢谢!
更新:
当我输出多行时,它们是左对齐的,但在实际数据之前有前导 17 space。请看下面的例子。此输出由上面的版本 2 代码生成。当我设置宽度为40时,实际宽度为95。
| gAaNbDxVTyFjjhgGodAKyy9uk |
| wMEzrsX2KKpTaJGE3uGEUibymG |
| 8cRzJOxCG7z qpfkXKgrQs6ubfOTK |
| A5a1lovY,yQoSHaYon5cGgo1l |
| f1mPa2ts2TUCbZ9UVmuDuu2lXLgfYTP |
代码中存在一些问题。
您应该在处理 width
时遵守 left
标志。 setw()
与 width()
基本相同,后者通常根据 left
标志左对齐或右对齐。请参阅 operator <<
以获取字符串:
- If
str.size()
is not less than os.width()
, uses the range
[str.begin(), str.end())
as-is
- Otherwise, if
(os.flags() & ios_base::adjustfield) == ios_base::left
, places os.width()-str.size()
, copies of the os.fill()
character after the character sequence
- Otherwise, places
os.width()-str.size()
copies of the os.fill()
character before the character sequence
padding用一次就清空是很常见的:os.width(0);
.
ostream_iterator
delegates to operator <<
对于 char
类型。该运算符将依次尝试填充,这将导致一团糟。
像这样
ostream& operator<<(ostream& os, const ByteArray& dt) {
size_t fill = os.width() > dt.len ? os.width() - dt.len : 0;
if ((os.flags() & ios_base::adjustfield) == ios_base::left) {
os.write((const char*)dt.ptr, dt.len);
fill_n(std::ostreambuf_iterator<char>(os), fill, os.fill());
}
else {
fill_n(std::ostreambuf_iterator<char>(os), fill, os.fill());
os.write((const char*)dt.ptr, dt.len);
}
os.width(0);
return os;
}
额外注意:测试填充时,谨慎的做法是在 和 之前打印一些内容。
我有一个表示字符串的自定义数据类型:
struct ByteArray {
uint32_t len;
uint8_t* ptr;
}
并覆盖 << 运算符以将其输出到屏幕。
版本 1:
ostream &operator<<(ostream &os, const ByteArray &dt) {
os << string((const char*)dt.ptr,dt.len);
return os;
}
版本 2:
ostream &operator<<(ostream &os, const ByteArray &dt) {
os.write((const char *) dt.ptr, dt.len);
auto fill = os.width() - dt.len;
fill_n(std::ostream_iterator<char>(os), fill, os.fill());
return os;
}
我的输出代码类似于
ByteArray& value = ...; // a string of length 25
cout << '|' << left << setw(40) << value;
当我使用版本 1 时,它运行良好并显示:
|gAaNbDxVTyFjjhgGodAKyy9uk
但是版本 2 显示 17 个前导空白 spaces:
| gAaNbDxVTyFjjhgGodAKyy9uk
我想使用版本 2,因为它不会创建不必要的字符串对象。但是我如何正确处理 setw 和 fill 呢?
谢谢!
更新:
当我输出多行时,它们是左对齐的,但在实际数据之前有前导 17 space。请看下面的例子。此输出由上面的版本 2 代码生成。当我设置宽度为40时,实际宽度为95。
| gAaNbDxVTyFjjhgGodAKyy9uk |
| wMEzrsX2KKpTaJGE3uGEUibymG |
| 8cRzJOxCG7z qpfkXKgrQs6ubfOTK |
| A5a1lovY,yQoSHaYon5cGgo1l |
| f1mPa2ts2TUCbZ9UVmuDuu2lXLgfYTP |
代码中存在一些问题。
您应该在处理
width
时遵守left
标志。setw()
与width()
基本相同,后者通常根据left
标志左对齐或右对齐。请参阅operator <<
以获取字符串:- If
str.size()
is not less thanos.width()
, uses the range[str.begin(), str.end())
as-is - Otherwise, if
(os.flags() & ios_base::adjustfield) == ios_base::left
, placesos.width()-str.size()
, copies of theos.fill()
character after the character sequence - Otherwise, places
os.width()-str.size()
copies of theos.fill()
character before the character sequence
- If
padding用一次就清空是很常见的:
os.width(0);
.ostream_iterator
delegates tooperator <<
对于char
类型。该运算符将依次尝试填充,这将导致一团糟。
像这样
ostream& operator<<(ostream& os, const ByteArray& dt) {
size_t fill = os.width() > dt.len ? os.width() - dt.len : 0;
if ((os.flags() & ios_base::adjustfield) == ios_base::left) {
os.write((const char*)dt.ptr, dt.len);
fill_n(std::ostreambuf_iterator<char>(os), fill, os.fill());
}
else {
fill_n(std::ostreambuf_iterator<char>(os), fill, os.fill());
os.write((const char*)dt.ptr, dt.len);
}
os.width(0);
return os;
}
额外注意:测试填充时,谨慎的做法是在 和 之前打印一些内容。