C++缩进重载ostream运算符

4

假设我有一些类,并通过重载左位移运算符来添加输出功能:

struct Foo
{
    int i = 1;
    std::string s = "hello";
};

auto& operator<<(std::ostream& os, Foo const& foo)
{
     os<<foo.i<<"\n";
     os<<foo.s<<"\n";
     return os;
}

什么是优秀的缩进输出方式?
示例:如果我写下以下代码:
std::cout<<"    "<<Foo{}<<std::endl;

输出结果为:
    1
hello

显然,“hello”没有缩进。有没有一种简单的方法来缩进整个输出(而不仅仅是第一个元素)?

用"os<<"\t"<<foo.i<<"\n"; os<<"\t"foo.s<<"\n";"替换。 - wyas
2
将内容打印到 stringstream 中并进行后处理?我不知道在 C++ 上的后处理会是什么样子,但应该不会太难。 - user2357112
@ColinBasnett:谢谢。我的问题有点不太明确,但我不认为stringstream处理是“容易”或“方便”的。此外,它无法复制一行的前导空格字符...当然,我可以解析换行符,但那甚至更不方便... - davidhigh
这里没有银弹,根据您当前的设置,您需要对写入流的数据执行后处理。当然,除非您想涉足拥有全局静态变量的令人担忧的世界,以跟踪当前缩进级别并在您的<<运算符中考虑它;但这是不良的程序设计,因为它使该代码无法在此缩进方案之外使用。 - Colin Basnett
你可能需要考虑如何在完全不使用 << 运算符的情况下实现这一点。如果没有更多关于你的程序目标和要求的信息,我们无法提供更具体的建议。 - Colin Basnett
显示剩余6条评论
2个回答

1
你正在对Foo对象进行序列化,对吧?因此,逻辑上,Foo的序列化字符串是Foo的实现细节。你可以编写自己的流类或类似的东西,但那会让问题过于复杂。
auto& operator<<(std::ostream& os, Foo const& foo)
{
    auto s = "\t" + std::to_string(foo.i) + "\n"
             "\t" + foo.s;
    return (os << s);
}

int main()
{
    std::cout << Foo{} << "\n";
}

0

您可以使用标准库操作符setw来设置字段的宽度,这通常会导致文本缩进。以下是使用方法:

cout << std::setw(10) << "Viola!" << std::endl;

这将打印出以4个空格缩进的单词"Viola!"。为什么是4个空格呢?setw()函数的参数决定了整个"字段"的宽度,其中包括"Viola!"中的6个字符。

默认情况下,setw()会将文本右对齐,但可以通过使用另一个操作符left来使其左对齐。以下是一个示例:

cout << std::setw(10) << std::left << "Viola!" << std::endl;

这将输出字符串"Viola!",没有缩进,但在它之后有4个空格。

这应该回答了你关于正确的缩进方式的问题,setw()不仅是一种好方法,而且是标准方法。

第二个问题询问如何实现持续的缩进,答案是没有简单的方法。最简单的方法是在每个cout调用中添加对setw()(或您使用的其他缩进方法)的调用。

除了以上答案,您还应该考虑将cout调用中的"\n"替换为对endl的调用。endl是“行尾”操作符,并使您的代码能够正常工作于任何输出流。代码看起来将会像这样:

auto& operator<<(std::ostream& os, Foo const& foo)
{
     os << foo.i << std::endl;
     os << foo.s << std::endl;
     return os;
}

谢谢。我的问题确切地涉及“持久缩进”部分。关于用std::endl替换\n:我想这通常会导致更差的性能,因为它意味着一个flush(实际上可能不需要)。 - davidhigh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接