c++ - C++ ostream 是否位于行首?
问题描述
在 C++ 中,如何检测 mystd::ostream os
是否位于行首,换句话说(我认为)最近写入的os
内容是os<<'\n'
or os<<std::endl()
,或者尚未写入任何内容os
?
乍一看,这听起来没有必要,因为我可以自己跟踪状态。但是下面是一个常见的情况,其中跟踪将涉及以非常不自然的方式更改os<<thing
可能从块中调用的每个语句。try
try {
do_something_which_writes_to(std::cout);
}
catch(const My_error&error) {
print_a_newline_if_necessary(std::cout);
std::cout<<error<<"\n";
}
(在现实中,当然,我们想写到error
,std::cerr
但通常会混在一起,std::cout
除非其中一个被重定向,所以我们仍然想std::cout
在打印到之前终止该行std::cerr
。我特意简化了示例以避免这种分心。)
您可能会认为这os.tellp()
将是答案,但tellp()
似乎仅适用于std::ofstream
. 至少对我来说,std::cout.tellp()
总是返回-1
,表示不支持。
解决方案
至少在我阅读内容时,您真正想要的不是获得当前行中的位置的能力。相反,您真正想要的是能够打印一些保证在行首的东西——如果前一个字符是换行符,则为当前行(而且,我猜它是否是一个马车return),否则打印一个换行符,然后是后面的任何内容。
这里有一些代码可以做到这一点:
#include <iostream>
class linebuf : public std::streambuf
{
std::streambuf* sbuf;
bool need_newline;
int sync() {
return sbuf->pubsync();
}
int overflow(int c) {
switch (c) {
case '\r':
case '\n': need_newline = false;
break;
case '\v':
if (need_newline) {
need_newline = false;
return sbuf->sputc('\n');
}
return c;
default:
need_newline = true;
break;
}
return sbuf->sputc(c);
}
public:
linebuf(std::streambuf* sbuf)
: sbuf(sbuf)
, need_newline(true)
{}
std::streambuf *buf() const { return sbuf; }
~linebuf() { sync(); }
};
class linestream : public std::ostream {
linebuf buf;
std::ostream &os;
public:
linestream(std::ostream& out)
: buf(out.rdbuf())
, std::ios(&buf)
, std::ostream(&buf)
, os(out)
{
out.rdbuf(&buf);
}
~linestream() { os.rdbuf(buf.buf()); }
};
void do_stuff() {
std::cout << "\vMore output\v";
}
int main() {
{
linestream temp(std::cout);
std::cout << "\noutput\n";
std::cout << "\voutput";
do_stuff();
std::cout << "\voutput\n";
std::cout << "\voutput\v";
}
std::cout << "\voutput\v";
}
由于它几乎从未以其他方式使用,因此我劫持了垂直制表符 ( '\v'
) 来表示特殊行为。
要使用它,您只需创建一个临时类型的对象linestream
(抱歉,我现在想不起一个好名字),传递给它一个 ostream 对象,当 a\v
被写入它时,该对象将获得新的行为。当该临时对象超出范围时,流将恢复到其原始行为(我怀疑是否有人\v
经常使用来关心,但谁知道也许有人关心——无论如何,这主要只是清理自身的副作用)。
在任何情况下,特殊行为在do_stuff
被调用时仍然存在,因此它不仅仅是创建本地对象的函数的本地linestream
对象,或者类似的东西——一旦它被创建,特殊行为就会一直有效,直到它被销毁。
不过还有一点:当/如果您混合来自cout
and的输出时cerr
,这将无济于事。特别是,双方都不会知道对方的状态。您可能非常需要一些挂钩到输出终端(或该订单上的某些东西)才能处理这个问题,因为输出重定向通常由操作系统处理,因此在程序内部甚至无法猜测数据是否写入去cout
和cerr
是否去同一个地方。
推荐阅读
- node.js - 调用 lambda 到 lambda 22 次并发花费太多时间
- python - 如何计算熊猫系列中的特定单词?
- android - Android VS Emulator 无法识别工作网络
- r - 将方程渲染为图像并使用 R Markdown 将它们包含在 Word/PowerPoint 输出文档中
- postgresql - PostgreSQL 在插入带有参数的外部脚本时触发
- sql - 删除子查询中的结果
- c++ - 如何读取我的 maxon 电机的速度状态?
- python - snakemake - 执行多项工作后工作流失败
- ios - 如何在 AppDelegate 中将默认声音添加到我的推送通知中
- windows - 命令“Get-Command -Module Defender”没有输出