在 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=] AB 的输出中(记住,我不能修改那些 classes)。实际上,B 为此直接使用了一个 ostream。我花了一些时间才意识到修改 ostream 的行为是唯一的方法,尽管它现在对我来说可能微不足道。

所以我需要做的是派生自 ostream 并修改其行为(特别是其方法operator<< 的行为)。事实证明,这是不可能的,因为 ostream::operator<< 没有多态性,因为它不是虚拟的。至少,我不认为它可以轻易实现(更不用说微不足道了)。