在 C++ 中,如何制作将未指定类型括在括号内的输出流?
How can I make an output stream that encloses unspecified types within brackets in C++?
Whosebug 的第一个计时器,请不要生吃我。
这是我的问题:我使用 classes 定义运算符 << 来输出它们的成员值。不幸的是,这些 classes 忘记了成员值可以是其他 classes 并且它们没有将自己括在(比方说)大括号之间以保持结构信息的完整性。 我不能修改这些 classes,我也没有关于它们结构的信息。这意味着我不能粗暴地浏览它们的内容。
为了这个例子,下面是一段代码,有两个 classes,A 和 B(其中 B 包含一个 class A)输出它们的成员变量("<variable_name>=<value>, "
).这是在 b:
的 cout 上使用 << 运算符的结果
cout << b; // yields: m_a=m_foo=43586, m_bar=43604, m_foo=47938
由此可见,无法判断A有一个成员变量还是两个成员变量(m_bar属于A还是B?)
我花了一些时间研究 ostream 的包装器,它会在既不是 C 风格字符串也不是整数的东西周围添加大括号。不幸的是,递归远没有我最初想象的那么简单。
produced result: B= { m_a=m_foo=43586, m_bar=43604, m_foo=47938 }
expected result: B= { m_a= { m_foo=43586, m_bar=43604 } , m_foo=47938 }
(但它非常适合 wrapper << 42 << "cstring" << variable_with_other_type;
)
这是我的问题:我这样做完全错了吗?我错过了一些明显的东西吗?我的问题的解决方案是否比我的方法复杂得多?
这是完整的代码(它需要 C++11 右值,但我坚持使用只有 -std=c++0x
的 gcc 的过时版本,所以它需要尽可能少C++11 as possible(将右值更改为 const 值以摆脱 C++11))。
#include <sstream>
#include <typeinfo>
using namespace std;
/* THIS BELOW CANNOT BE MODIFIED */
class A
{
public:
A(){
m_foo=0xAA42;
m_bar=0xAA54;
};
virtual ~A(){};
friend ostream& operator<<(ostream& os, const A& a);
int m_foo;
int m_bar;
};
class B
{
public:
B(A a) {
m_foo = 0xBB42;
m_a = a;
}
virtual ~B(){};
friend ostream& operator<<(ostream& os, const B& b);
A m_a;
int m_foo;
};
ostream& operator<<(ostream& os, const A& a)
{
// os << "{"; // woops forgot to uncomment this
os << "m_foo=" << a.m_foo;
os << ", ";
os << "m_bar=" << a.m_bar;
// os << "}"; // woops forgot to uncomment this
return os;
}
ostream& operator<<(ostream& os, const B& b)
{
// os << "{"; // woops forgot to uncomment this
os << "m_a=" << b.m_a;
os << ", ";
os << "m_foo=" << b.m_foo;
// os << "}"; // woops forgot to uncomment this
return os;
}
/* THIS BELOW CAN BE MODIFIED */
class WrappingOstream
{
public:
WrappingOstream(ostream& stream);
virtual ~WrappingOstream();
template <class T> WrappingOstream& operator<<(const T& x) {
m_stream << " { " << x << " } ";
//*this << " { " << x << " } "; //segfaults when replacing m_stream with *this
return *this;
}
WrappingOstream& operator<<(int i)
{
m_stream << i;
return *this;
}
WrappingOstream& operator<<(const char* cstr)
{
m_stream << cstr;
return *this;
}
private:
ostream& m_stream;
};
WrappingOstream::WrappingOstream(ostream& stream) :
m_stream(stream)
{
//ctor
}
WrappingOstream::~WrappingOstream()
{
//dtor
}
int main() {
A a;
B b(a);
ostringstream ss;
WrappingOstream wos(ss);
wos << b << endl;
cout << "produced result: B=" << ss.str();
cout << "expected result: B=" << " { m_a= { m_foo=43586, m_bar=43604 } , m_foo=47938 }";
}
提前致谢,
就是因为这段代码:
template <class T> WrappingOstream& operator<<(const T& x) {
m_stream << " { " << x << " } ";
当您在 main
中传递 B 时,您使用的是 WrappingOstream,但在 operator<<
中您使用的是 m_stream
,这是一个普通的 std::ostream
.因此,当您打印 A 时,它会调用通用 operator<<
而不是 WrappingOstream
中的那个。尝试向这些方法添加调试打印输出以查看何时调用什么。
您可以通过直接将 std::ostringstream
子类化为 WrappingOstream
.
来解决这个问题
好的,归结为:
我正在尝试做的具体事情显然是不可能实现的。为什么会这样并不是没有兴趣,所以,这就是原因。回到我的问题。
我真正需要做的是不环绕ostream,因为这意味着我无法劫持[=的深度打印28=] A
在 B
的输出中(记住,我不能修改那些 classes)。实际上,B 为此直接使用了一个 ostream。我花了一些时间才意识到修改 ostream 的行为是唯一的方法,尽管它现在对我来说可能微不足道。
所以我需要做的是派生自 ostream 并修改其行为(特别是其方法operator<<
的行为)。事实证明,这是不可能的,因为 ostream::operator<<
没有多态性,因为它不是虚拟的。至少,我不认为它可以轻易实现(更不用说微不足道了)。
Whosebug 的第一个计时器,请不要生吃我。
这是我的问题:我使用 classes 定义运算符 << 来输出它们的成员值。不幸的是,这些 classes 忘记了成员值可以是其他 classes 并且它们没有将自己括在(比方说)大括号之间以保持结构信息的完整性。 我不能修改这些 classes,我也没有关于它们结构的信息。这意味着我不能粗暴地浏览它们的内容。
为了这个例子,下面是一段代码,有两个 classes,A 和 B(其中 B 包含一个 class A)输出它们的成员变量("<variable_name>=<value>, "
).这是在 b:
cout << b; // yields: m_a=m_foo=43586, m_bar=43604, m_foo=47938
由此可见,无法判断A有一个成员变量还是两个成员变量(m_bar属于A还是B?)
我花了一些时间研究 ostream 的包装器,它会在既不是 C 风格字符串也不是整数的东西周围添加大括号。不幸的是,递归远没有我最初想象的那么简单。
produced result: B= { m_a=m_foo=43586, m_bar=43604, m_foo=47938 }
expected result: B= { m_a= { m_foo=43586, m_bar=43604 } , m_foo=47938 }
(但它非常适合 wrapper << 42 << "cstring" << variable_with_other_type;
)
这是我的问题:我这样做完全错了吗?我错过了一些明显的东西吗?我的问题的解决方案是否比我的方法复杂得多?
这是完整的代码(它需要 C++11 右值,但我坚持使用只有 (将右值更改为 const 值以摆脱 C++11))。 -std=c++0x
的 gcc 的过时版本,所以它需要尽可能少C++11 as possible
#include <sstream>
#include <typeinfo>
using namespace std;
/* THIS BELOW CANNOT BE MODIFIED */
class A
{
public:
A(){
m_foo=0xAA42;
m_bar=0xAA54;
};
virtual ~A(){};
friend ostream& operator<<(ostream& os, const A& a);
int m_foo;
int m_bar;
};
class B
{
public:
B(A a) {
m_foo = 0xBB42;
m_a = a;
}
virtual ~B(){};
friend ostream& operator<<(ostream& os, const B& b);
A m_a;
int m_foo;
};
ostream& operator<<(ostream& os, const A& a)
{
// os << "{"; // woops forgot to uncomment this
os << "m_foo=" << a.m_foo;
os << ", ";
os << "m_bar=" << a.m_bar;
// os << "}"; // woops forgot to uncomment this
return os;
}
ostream& operator<<(ostream& os, const B& b)
{
// os << "{"; // woops forgot to uncomment this
os << "m_a=" << b.m_a;
os << ", ";
os << "m_foo=" << b.m_foo;
// os << "}"; // woops forgot to uncomment this
return os;
}
/* THIS BELOW CAN BE MODIFIED */
class WrappingOstream
{
public:
WrappingOstream(ostream& stream);
virtual ~WrappingOstream();
template <class T> WrappingOstream& operator<<(const T& x) {
m_stream << " { " << x << " } ";
//*this << " { " << x << " } "; //segfaults when replacing m_stream with *this
return *this;
}
WrappingOstream& operator<<(int i)
{
m_stream << i;
return *this;
}
WrappingOstream& operator<<(const char* cstr)
{
m_stream << cstr;
return *this;
}
private:
ostream& m_stream;
};
WrappingOstream::WrappingOstream(ostream& stream) :
m_stream(stream)
{
//ctor
}
WrappingOstream::~WrappingOstream()
{
//dtor
}
int main() {
A a;
B b(a);
ostringstream ss;
WrappingOstream wos(ss);
wos << b << endl;
cout << "produced result: B=" << ss.str();
cout << "expected result: B=" << " { m_a= { m_foo=43586, m_bar=43604 } , m_foo=47938 }";
}
提前致谢,
就是因为这段代码:
template <class T> WrappingOstream& operator<<(const T& x) {
m_stream << " { " << x << " } ";
当您在 main
中传递 B 时,您使用的是 WrappingOstream,但在 operator<<
中您使用的是 m_stream
,这是一个普通的 std::ostream
.因此,当您打印 A 时,它会调用通用 operator<<
而不是 WrappingOstream
中的那个。尝试向这些方法添加调试打印输出以查看何时调用什么。
您可以通过直接将 std::ostringstream
子类化为 WrappingOstream
.
好的,归结为:
我正在尝试做的具体事情显然是不可能实现的。为什么会这样并不是没有兴趣,所以,这就是原因。回到我的问题。
我真正需要做的是不环绕ostream,因为这意味着我无法劫持[=的深度打印28=] A
在 B
的输出中(记住,我不能修改那些 classes)。实际上,B 为此直接使用了一个 ostream。我花了一些时间才意识到修改 ostream 的行为是唯一的方法,尽管它现在对我来说可能微不足道。
所以我需要做的是派生自 ostream 并修改其行为(特别是其方法operator<<
的行为)。事实证明,这是不可能的,因为 ostream::operator<<
没有多态性,因为它不是虚拟的。至少,我不认为它可以轻易实现(更不用说微不足道了)。