W. *_*man 13 c++ operator-overloading indentation stream
在我们的项目中,我们在对象模型中使用c ++流操作符(<<)来打印出易于读取的数据格式.一个简单的例子是这样的:
std::ostream& operator<<(std::ostream & oStream, const OwnClass& iOwnClass) {
oStream << "[SomeMember1: " << iOwnClass._ownMember1 << "]\n";
oStream << "[SomeMember2: " << iOwnClass._ownMember2 << "]\n";
}
Run Code Online (Sandbox Code Playgroud)
在日志中导致这种情况:
[SomeMember1: foo]
[SomeMember2: bar]
Run Code Online (Sandbox Code Playgroud)
我们现在想要的是能够缩进该运算符的结果.某些调用类可能不希望得到这样的结果,但是想要在每行之前添加2个空格.我们可以在我们的类中添加一个指定缩进的成员,但这似乎不是一个优雅的解决方案.
当然这不是一个很大的问题,但是如果这样做的话,我们的日志记录会更好.
谢谢
Jam*_*nze 25
最简单的解决方案是ostream在实际的streambuf 之间滑动过滤
streambuf.就像是:
class IndentingOStreambuf : public std::streambuf
{
std::streambuf* myDest;
bool myIsAtStartOfLine;
std::string myIndent;
std::ostream* myOwner;
protected:
virtual int overflow( int ch )
{
if ( myIsAtStartOfLine && ch != '\n' ) {
myDest->sputn( myIndent.data(), myIndent.size() );
}
myIsAtStartOfLine = ch == '\n';
return myDest->sputc( ch );
}
public:
explicit IndentingOStreambuf(
std::streambuf* dest, int indent = 4 )
: myDest( dest )
, myIsAtStartOfLine( true )
, myIndent( indent, ' ' )
, myOwner( NULL )
{
}
explicit IndentingOStreambuf(
std::ostream& dest, int indent = 4 )
: myDest( dest.rdbuf() )
, myIsAtStartOfLine( true )
, myIndent( indent, ' ' )
, myOwner( &dest )
{
myOwner->rdbuf( this );
}
virtual ~IndentingOStreambuf()
{
if ( myOwner != NULL ) {
myOwner->rdbuf( myDest );
}
}
};
Run Code Online (Sandbox Code Playgroud)
要插入,只需创建streambuf的实例:
IndentingOStreambuf indent( std::cout );
// Indented output...
Run Code Online (Sandbox Code Playgroud)
如果indent超出范围,一切恢复正常.
(对于日志记录,我有一个更复杂:
LoggingOStreambuftake __FILE__和__LINE__as参数,设置
myIndent为带有这些参数的格式化字符串,加上时间戳,在每次输出后将其重置为缩进字符串,收集所有输出an std::ostringstream,并以原子方式将myDest其输出到析构函数中.)
这可以使用自定义流操纵器来完成,该操纵器将所需的缩进级别存储在流的内部可扩展数组的字中。您可以使用 函数 请求这样的单词ios_base::xalloc。该函数将为您提供单词的索引。您可以使用 访问它ios_base::iword。实现这一点的一种方法是这样的:
struct indent {
indent(int level) : level(level) {}
private:
friend std::ostream& operator<<(std::ostream& stream, const indent& val);
int level;
};
std::ostream& operator<<(std::ostream& stream, const indent& val) {
for(int i = 0; i < val.level; i++) {
stream << " ";
}
return stream;
}
std::ostream& operator<<(std::ostream & oStream, const OwnClass& iOwnClass) {
oStream << indent(oStream.iword(index)) << "[SomeMember1: " <<
iOwnClass._ownMember1 << "]\n";
oStream << indent(oStream.iword(index)) << "[SomeMember2: " <<
iOwnClass._ownMember2 << "]\n";
}
Run Code Online (Sandbox Code Playgroud)
您必须弄清楚在哪里存储index. 这实际上允许您向流添加自定义状态(请注意,这不是开箱即用的线程安全)。每个需要缩进的函数都应该将请求的缩进添加到流中,并在完成后再次减去它。您可以通过使用防护来添加/减去所需的缩进来确保这种情况始终发生(恕我直言,这比使用操纵器更优雅):
class indent_guard {
public:
indent_guard(int level, std::ostream& stream, int index)
: level(level),
stream(stream),
index(index)
{
stream.iword(index) += level;
}
~indent_guard() {
stream.iword(index) -= level;
}
private:
int level;
std::ostream& stream;
int index;
};
Run Code Online (Sandbox Code Playgroud)
你可以这样使用它:
void some_func() {
indent_guard(2, std::cout, index);
// all output inside this function will be indented by 2 spaces
some_func(); // recursive call - output will be indented by 4 spaces
// here it will be 2 spaces again
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6046 次 |
| 最近记录: |