Hi,
I have a problem with extending some existing code. In a simplified
form, the problem looks like this:
I have four types, A, B, C, and D. Each A refers to zero, one, or more
B's and each B can be child to zero, one, or more A's. I just call that
"A is a parent of B", and "B is a child of A". The same goes for B and
C and for C and D. So A is only a parent, B and C are both parents and
children, and D is only a child.
I have many algorithms dealing with these. Most them are templates and
work on either all types, or all parent types, or all child types (and
some even only work on grandparent types). For this to work, the types
look somewhat like this:
// Beware, uncompiled code ahead!
struct tmp_nil {};
template<bool b> struct tmp_bool { enum {result=b}; };
class A;
class B;
class C;
class D;
class A {
public:
typedef tmp_bool<false> is_child;
typedef tmp_bool<true > is_parent;
typedef B child_t;
};
class B {
public:
typedef tmp_bool<true > is_child;
typedef tmp_bool<true > is_parent;
typedef A parent_t;
typedef C child_t;
};
class C {
public:
typedef tmp_bool<true > is_child;
typedef tmp_bool<true > is_parent;
typedef B parent_t;
typedef D child_t;
};
class D {
public:
typedef tmp_bool<true > is_child;
typedef tmp_bool<false> is_parent;
typedef C parent_t;
};
For example, if some algorithm needs to work on a type and recursivly
on all children and grandchildren, what the code does is this:
class some_class {
public:
//...
// this is called by users and does the recursive downstepping
template<class T> void some_algorithm(const T& obj)
{
// do some real work with 'obj'
detail::some_algorithm_(obj,typename T::is_parent()); // recurse
}
//...
private:
//...
// some_algorithm()'s implementation for parents
template<class T> void some_algorithm_(const T& obj, tmp_bool<true > /*is_parent*/)
{
for( <all children refered to by 'obj'> ) {
typename T::child_t& child = /*...*/;
some_algorithm(child);
}
}
// some_algorithm()'s implementation for childless types
template<class T> void some_algorithm_(const T& obj, tmp_bool<false> /*is_parent*/)
{
// no children, so nothing to do here
}
//...
};
This worked all very well for years. However, now my task is to introduce
some type B2, that's also a child to A (but not a parent to C):
class B2 {
public:
typedef tmp_bool<true > is_child;
typedef tmp_bool<false> is_parent;
typedef A parent_t;
};
Now, I suppose parents would need to change like this:
template<typename Head, class Tail> struct tmp_list {};
class A {
public:
typedef tmp_bool<false> is_child;
typedef tmp_bool<true > is_parent;
typedef tmp_list< B, tmp_list<C,tmp_nil> >
child_list;
};
I know how to deal with such recursive type lists. However, I only know
how to do this with _class_ templates. But it's _functon_ templates that
I have as algorithms, and they are stuck in some class (the 'some_class'
in the example above above) that provides all the necessary functionality
(retrieve objects etc.) for them. (And they also need to be members of it
because 'some_class', in reality being a friend to A, B, C, and D, is the
only thing that can actually get at the relevant information -- which is
not needed by users of A, B, C, and D.)
So given
template<class T> void some_class::some_algorithm_(const T&,tmp_bool<true>)
how can I make it call
template<class T> void some_class::some_algorithm(const T&)
for _all_ children in the child list of (the new version of) A?
As for the constraints I'm working under: The code is "mine". I am free
to change it as I need as long as the public interface doesn't change
more than ansolutely necessary. It is, however, quite a lot of code,
with many algorithms that have been maintained and fixed for years. And,
as always, the deadline is a rather tight one.
That's why I want to "implant" B2 with as little changes as necessary.
Right now it seems it's just a syntactic problem.
TIA,
Schobi
--
Sp******@gmx.de is never read
I'm Schobi at suespammers dot org
"The sarcasm is mightier than the sword."
Eric Jarvis