[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
XTL patches, problems, features
- To: xtl@lsd.di.uminho.pt
- Subject: XTL patches, problems, features
- From: Lutz Latta <lutz@latta.de>
- Date: Tue, 21 Nov 2000 14:15:42 +0000
- Delivered-To: mailing list xtl@lsd.di.uminho.pt
- Mailing-List: contact xtl-help@lsd.di.uminho.pt; run by ezmlm
- Reply-To: lutz@latta.de
Hi XTLers,
I recently used XTL in a project (a computer game on Win32)
and had to do quite a lot of adjustments to make XTL work
the way I wanted.
Some of the stuff concerns compiler specific problems
(MS VC++ 6.1), which you probably want to include in the
main distribution. Other things are new features (making
auto_object work in deeper nested calls; using iostreams as
output etc.). With some software design issues I'm not so
happy - decide want you want to include in the distribution.
Most of the changes I did in the auto_obj_input/output
classes since I only used these. Some of them would be
relevant to obj_*put as well.
1) The XTL_COMPOSITE_BUG. In one of the earlier patches to
XTL1.3 a problem with template specialization with the MSVC
compiler was fixed by introducing some compiler defines and
workarounds. They are generally not neccessary at the point
they were used - since MSVC is able to handle template
specialization. The only requirement is that the
specialized function comes AFTER the more general one (for
whatever reason...). In the obj_input/output classes the
function
template <class T>
inline obj_input& simple(T& data) {...}
needs to be above the specialized functions, declared by
def_simple_input(...);
If there is no problem with this order in other compilers,
than the XTL_COMPOSITE_BUG define can be removed.
2) But there is another problem with template
specialization in MSVC. The compiler does not regard a
template with just one parameter to be more specialized
than a template with two parameters.
This functionality is used in XTL to enable the
serialization of third-party classes. The global-scope
function
template <class Stream, class T>
inline void composite(Stream& stream, T& data) {...}
is not regarded as a less specialized function than
template <class Stream>
inline void composite(Stream& stream, MyType& data) {...}
There are two ways to work around this. Either you write
two or more functions without any function template for
every stream you have, e.g.
inline void composite(obj_input& stream, MyType& data);
inline void composite(obj_output& stream, MyType& data);
or you could use a different function in the streams to
serialize third-party classes. I chose the latter approach,
because I did not want the code-doubling of the first (Can
anyone think of compiler macros or whatever to work around
this?). I introduced to the auto_obj_*put classes a method
called special() that calls a global-scope function called
special for the data type of its parameter. The
disadvantage of this approach, is that the third-party data
types cannot be serialized by other methods like array() or
vector() any more. As an example I added a special_array()
method to serialize arrays of third-party data types, which
I had a lot of.
3) A small type check problem: In graphio.h there is a map
to translate the graph indices to pointers and vice versa.
The type was defined as
typedef std::map<void*,int> trans_type;
but is used as a map in both directions, sometimes filled
with an int as key and a void* as second value. I got some
error messages with my compiler settings, and therefore
split the type into two, one with a map for input and one
for output operations.
4) I had quite a big problem with getting auto_object_*put
to really work. Has it ever been tested on a real class
hierarchy? The problem is that it works fine, if you call
auto_object() from the main application, for a stream
variable you declared there. But when you serialize a whole
tree of classes, the type of the stream (=auto_obj_*put) is
lost when any of the inherited methods in obj_*put is used
for serializing the first level of the object hierarchy.
The obj_*put methods basically do an implicit up-cast with
the stream variable, and I don't see an elegant way to
down-cast it to an auto_obj_*put type without the ability
to use virtual methods on templates.
The very ugly way I worked around this is by copying all
the serialization methods from the obj_*put classes to the
auto_obj_*put classes and changing all the stream types
used by them to auto_obj_*put. If anyone can think of a
better way, please let me know. There is the remote
possibility that the problem just exists with the MSVC
compiler, but I don't think so.
5) I needed a graph reference system like the one in
graphio.h that works with the auto_obj_*put classes. The
problem here is that the classes cannot be templates that
use the reference class as a parameter.
Instead I introduced a small interface with a class
heritance which was supposed to be exchangeble just by
standard dynamic linkage - so that you still could choose
between a no-reference and a graph-reference system or
whatever. I didn't really get it to work and didn't care
that much after the graph system worked. But the classes
are all there and you could choose something else than
graph references by changing the type of the refs member
variable in the auto_obj_*put classes.
Note that the auto_object() function automatically uses the
reference system, just like the reference() function. In
case you don't want the overhead of this, you can use
auto_object_noref() instead.
6) Another method I added to the auto_obj_*put classes is
object_container(), which works like container(), but calls
auto_object() instead of simple() on any of the items in
the container.
7) Something that I haven't changed yet, but thought about
doing it: I don't really like the idea of having to build
the whole externalizable_index in one source file, instead
of declaring every class in its own source. A few
experiments with this showed that there is a problem with
the order of execution - since you don't have any control
over the order the initialization code of the source files
is executed.
I think this problem might be avoided by using a singleton
pattern for the externalizable_index variable instead of a
global variable, but I didn't have time to try it out yet.
8) Two really minor things:
I renamed the reader classes in
autoio.h. I changed it to "creator" and similar, because
they don't really read anything.
I added a few empty method bodies to the text_format class,
because it didn't compile for a test without them.
9) And finally: I did it - a simple system of buffer classes
that work with C++ iostreams - just to help you with the
once promised feature of being able to write to C++
streams... The file is called iostrbuf.h
That's all. If you're still reading this, you're probably
still interested in XTL, and I hope you don't hate me for
ruining your piece of delicate software artwork :-)
I really like XTL and appreciate your effort in its
development. Thank you.
Tell me what you think about my changes,
Lutz Latta
----------------------------------------
Lutz Latta
Email: lutz@latta.de
"University of the West of England"
xtl.ll.diff.gz