首页 > 解决方案 > 如何处理自定义输出运算符中的iomanips?

问题描述

我刚刚遇到了将自定义输出运算符与 io-manipulators 相结合的问题。也许我的期望完全偏离了,但如果

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-manipulators 的惯用方式是什么?

标签: c++iomanip

解决方案


恐怕没有简单的答案。如果您只需要处理std::setwand ,您的解决方案是惯用的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例如 。


推荐阅读