如何处理自定义输出运算符中的 iomanips?
How to deal with iomanips in custom output operators?
我刚刚遇到了将自定义输出运算符与io操纵器结合使用的问题。也许我的期望完全偏离了,但如果
std::cout << foo() << "n";
指纹
00
那么我会期待
std::cout << std::left << std::setw(20) << foo() << "!n"
要打印
00 !
但鉴于此实现
#include <iostream>
#include <iomanip>
struct foo { int a,b; };
std::ostream& operator<<(std::ostream& out, const foo& f) {
out << f.a << f.b;
return out;
}
int main() {
std::cout << foo() << "n";
std::cout << std::left << std::setw(20) << foo() << "!";
}
屏幕上打印的是
00
0 0!
我基本上看到两种选择:A(我的期望是错误的。B( 我改用这个实现:
std::ostream& operator<<(std::ostream& out, const foo& f) {
std::stringstream ss;
ss << f.a << f.b;
out << ss.str();
return out;
}
但是,考虑到大多数时候没有使用 io 操纵器,这似乎需要相当大的开销。
在自定义输出运算符中"正确"处理io操纵器的惯用方法是什么?
恐怕没有简单的答案。如果您只需要处理
std::setw
和std::left
,您的解决方案是惯用的,但是对于其他操作,您必须决定格式化程序的行为。例如,想象一下,如果你的结构有浮点数而不是整数:
struct foo { float a,b; };
然后,您的用户尝试执行此操作:
const long double pi = std::acos(-1.L);
std::cout << std::setprecision(10) << foo{0.0f, pi} << "!n"
这是您必须决定的时候:是要尊重输出流的精度属性,还是要忽略它?您当前的实现将忽略它,因为它在另一个流中执行实际转换。
若要遵循精度属性,必须复制它:
std::ostream& operator<<(std::ostream& out, const foo& f) {
std::stringstream ss;
ss.precision(out.precision());
ss << f.a << f.b;
out << ss.str();
return out;
}
对于整数的情况,您还必须考虑是否遵守std::setbase
。
同样的推理必须应用于其他操纵器,例如std::setfill
。
不一定是惯用语,但一种可能的发音是这样的:
struct foo {
int a,b;
std::string toString() {
std::stringstream ss;
ss << a << b;
return ss.str();
}
};
std::ostream& operator<<(std::ostream& out, const foo& f) {
out << a << b;
return out;
};
现在,调用方可以选择输出是否应该作为一个整体:
std::cout << std::left << std::setw(20) << foo().toString() << "!"; // output as expected
std::cout << foo(); // output as expected
// and no unnecessary overhead
有人可能还会争辩说,输出已经很慢了,所以一点额外的开销并没有什么坏处,只需根据 stringify 方法实现输出运算符:
std::ostream& operator<<(std::ostream& out, const foo& f) {
out << f.toString();
return out;
}
这也修复了第一种方法的小丑陋,该方法基本上用几乎相同的代码实现相同的事情两次。
相关文章:
- 为什么比较运算符如此快速
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 使用C++中的模板和运算符重载执行矩阵运算
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 增量运算符与后缀混淆
- 一个关于在C++中重载布尔运算符的问题
- 运算符C++ "delete []"仅删除 2 个前值
- 模板类无法识别友元运算符
- 我可以使用条件运算符初始化C风格的字符串文字吗
- 关闭||运算符优化
- 通过继承类使用来自不同命名空间的运算符
- C++Cast运算符过载
- 如何使用AngelScript注册SFML Vector2运算符
- 重载元组索引运算符-C++
- 如何使用重载的相等(==)运算符向测试用例添加描述
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- 布尔比较运算符是如何在C++中工作的
- 重载运算符new[]的行为取决于析构函数
- 如何处理自定义输出运算符中的 iomanips?