|
Boost : |
From: Michel André (michel.andre_at_[hidden])
Date: 2002-09-11 14:37:15
> > Oh... I thought about variable names too! Did I understood correctly
> > that you use scheme with const and non-const 'describe'?
>
> Here is what I do currently:
>
> struct X
> {
> explicit X(int i = 0): i(i)
> {
> }
>
> virtual ~X()
> {
> }
>
> int i;
> };
>
> template<class R> void read(R & r, X & x)
> {
> begin_struct(r);
> read(r, x.i);
> end_struct(r);
> }
>
> template<class W> void write(W & w, X const & x)
> {
> begin_struct(w);
> write(w, x.i);
> end_struct(w);
> }
>
> template<class W, class A> void write(W & w, X const & x, A const & a)
> {
> begin_struct(w, a);
> write(w, x.i, "i");
> end_struct(w, a);
> }
>
> This is quite repetitive and error-prone, but without
reflection/metadata...
Actually I use a similar aproach to describe/serialize objects. This is a
minimalist example showing my approach..
#include <iostream>
#include <typeinfo.h>
#include <sstream>
template<typename DATA>
struct Description
{};
struct Person
{
Person() {}
Person(const std::string& firstName, const std::string& lastName, int
birthYear) : m_firstName(firstName), m_lastName(lastName),
m_birthYear(birthYear) {}
std::string m_firstName;
std::string m_lastName;
int m_birthYear;
};
template<>
struct Description<Person>
{
template<typename STRUCT, typename VISITOR>
static void Describe(STRUCT& data, VISITOR& visitor)
{
visitor.Begin(data);
visitor.Attribute(data.m_firstName, "FirstName");
visitor.Attribute(data.m_lastName, "LastName");
visitor.Attribute(data.m_birthYear, "BirthYear");
visitor.End(data);
}
};
template<>
struct Description<const Person> : public Description<Person> {} //
Specialization for deficient compiler
template<typename STRUCT, typename VISITOR>
void Describe(STRUCT& data, VISITOR& visitor)
{
Description<STRUCT>::Describe(data, visitor);
// For non deficient compilers
//Description< boost::remove_const<STRUC>::type>::Describe(data,
visitor);
};
class Writer
{
std::ostream* m_stream;
public:
Writer(std::ostream& stream) : m_stream(&stream) {}
template<typename STRUCT>
void Begin(const STRUCT& data)
{
*m_stream << "Begin:" << typeid(data).name() << std::endl;
}
template<typename STRUCT>
void End(const STRUCT& data)
{
*m_stream << "End:" << typeid(data).name() << std::endl;
}
template<typename ATTRIBUTE>
void Attribute(const ATTRIBUTE& attribute, const std::string& name)
{
*m_stream << name.c_str() << "{" << typeid(attribute).name() << "}=
" << attribute << std::endl;
}
template<>
void Attribute(const std::string& attribute, const std::string&
name)
{
*m_stream << name.c_str() << "= " << attribute.c_str() << std::endl;
}
};
class Reader
{
std::istream* m_stream;
public:
Reader(std::istream& stream) : m_stream(&stream) {}
template<typename STRUCT>
void Begin(STRUCT& data, const std::string& name)
{
std::string s;
std::getline(*m_stream,s);
}
template<typename STRUCT>
void End(STRUCT& data, const std::string& name)
{
std::string s;
std::getline(*m_stream,s);
}
template<typename ATTRIBUTE>
void Attribute(ATTRIBUTE& attribute, const std::string& name)
{
std::string s;
*m_stream >> s >> attribute;
}
};
int main(int argc, char* argv[])
{
Person p("Michel", "Andre", 1971);
std::stringstream ss;
Writer w(ss);
Describe(p, w);
Person p1;
Reader r(ss);
Describe(p1, r);
Writer w1(std::cout);
Describe(p1, w1);
return 0;
}
I beleive this is const safe since STRUCT& can be bound to const Person& if
a const safe version is needed.
It also solves the problem with needing two or 3 separate description/stream
functions. The version we use is a bit more sophisticated but this is the
base (Basically the Description class is used as a streaming policy traits
class containing more information about a type and also carrying information
if a class has a specialized description and an unique string and numeric id
for the type). All error detection is omitted. I have 4 formats today a xml,
binary, text, db.
Maybe this approach could be modified and used to build a serialization
library on? At least I've used it successfully in several projects, but
maybe the a aproach is to simplistic for a complex streaming library.
Regards
/Michel
PS. I've probably should give a tons of credits for this but I have refined
an idea from a colleague who read an article in CUJ or C++ Report I haven't
been able to find it, maybe someone of you can helo me so I can give due
credits for the solution DS.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk