On Tue, Nov 19, 2002 at 06:07:23PM +0100, Wesley W. Terpstra wrote:
> The trick is to use the FUNCTION boundary of the serializor.

<snip code>

I have attached a working proto-type.

This is merely proof of concept; I am not sure whether one should bracket
fundamental types for instance.

The output is presently:
        [ 1 [ 2 ] 3 4 [ 5 ] ] 
but maybe should be:
        [ [1] [ [2] ] [3] [4] [ [5] ] ]

What do people think?
I am certain someone smarter than I could make this even more clever.

---
Wes

//-------------------------------------------------------- Example begins
// Compiles and works with g++-2.95.4

#include <iostream>
using namespace std;

//-------------------------------------------------------- Common Framework

class object_stream;

class streamer
{
 protected:
        object_stream*  m_impl;
        streamer(object_stream* stream) : m_impl(stream) { }
        
 public:
        template <class T>
        object_stream& operator << (const T& x);
        
 friend class object_stream;
};

class object_stream
{
 protected:
        streamer m_helper;
        
        virtual void object_begin() = 0;
        virtual void object_end  () = 0;
        
 public:
        object_stream() : m_helper(this) { }
        virtual ~object_stream() { }
        
        operator streamer& ()
        {       // Casted on return from method
                object_end();
                return m_helper;
        }
        
        // All fundamental types go here
        virtual object_stream& operator << (int x) = 0;
        
        // This catches all non-fundamental types and safely preserves
        // our type information while calling 
        template <class T>
        object_stream& operator << (const T& x)
        {       // Don't use conversion routine to cast us (not end of object)
                return *(m_helper << x).m_impl;
        }
 
 friend class streamer;
};

template <class T>
object_stream& streamer::operator << (const T& x)
{
        m_impl->object_begin();
        return *m_impl << x;
}

//-------------------------------------------------------- Concrete streamer

class paran_object_stream : public object_stream
{
 protected:
        void object_begin() { cout << "[ "; }
        void object_end  () { cout << "] ";  }
 
 public:
        paran_object_stream& operator << (int x)
        { cout << x << " "; return *this; }
};

class paran_streamer : public streamer
{
 protected:
        paran_object_stream m_obj;
        
 public:
        paran_streamer()
         : streamer(&m_obj) // a bit bad since it is not init'd, but since
        { }                 // we won't do anything in the base-class, ok
};

//-------------------------------------------------------- Generic user

struct Foo
{
        int x;
};

streamer& operator << (streamer& o, const Foo& f)
{ return o << f.x; }

struct Bar
{
        int a;
        Foo b;
        int c;
        int d;
        Foo e;
};

streamer& operator << (streamer& o, const Bar& b)
{ return o << b.a << b.b << b.c << b.d << b.e; }

//-------------------------------------------------------- test

int main()
{
        Bar b;
        b.a = 1;
        b.b.x = 2;
        b.c = 3;
        b.d = 4;
        b.e.x = 5;
        
        paran_streamer s;
        
        s << b;
        cout << endl;
}
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Reply via email to