Boost logo

Boost :

From: Wesley W. Terpstra (terpstra_at_[hidden])
Date: 2002-11-19 14:30:45


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;
}

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk