By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
448,953 Members | 1,123 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 448,953 IT Pros & Developers. It's quick & easy.

a template meta problem

P: n/a
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
Dec 1 '05 #1
Share this Question
Share on Google+
6 Replies


P: n/a
Hendrik Schober wrote:
Hi,

I have a problem with extending some existing code. In a simplified
form, the problem looks like this: .... Right now it seems it's just a syntactic problem.


Any chance of creating a brief and compilable piece. I don't get
exactly how B2 plays into this.
Dec 1 '05 #2

P: n/a
Hendrik Schober wrote:
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
No namespace/class called detail is given. I'm assuming that you meant
to call the private template member functions given below and not a
function that is not shown.
}

//...

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 think you meant B2 not C in this typedef.
};

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?

[snip]

Before we can answer that, I think we need to see how you plan to
reference children of A. You have given us the typedef for the child
list, but how do you declare a child (or a pointer or reference to a
child) which is a member of A and a type in that list?

Cheers! --M

Dec 1 '05 #3

P: n/a
Gianni Mariani <gi*******@mariani.ws> wrote:
Hendrik Schober wrote:
Hi,

I have a problem with extending some existing code. In a simplified
form, the problem looks like this: ...
Right now it seems it's just a syntactic problem.


Any chance of creating a brief and compilable piece.


My problem is that I have no idea what a compilable
piece would look like.
I don't get
exactly how B2 plays into this.

It's a sibling to B, except that it isn't a parent to C.

Schobi

--
Sp******@gmx.de is never read
I'm Schobi at suespammers dot org

"The sarcasm is mightier than the sword."
Eric Jarvis
Dec 1 '05 #4

P: n/a
mlimber <ml*****@gmail.com> wrote:
[...]
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
No namespace/class called detail is given. I'm assuming that you meant
to call the private template member functions given below and not a
function that is not shown.


Yep. Sorry for that. I first made this example using
free functions. Only later I realized that the fact
that they are members might be of some (syntactic)
significance. So I changed the example and forgot
this.
[...]
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 think you meant B2 not C in this typedef.


Um, yeah. Sorry. :(
[...]

Before we can answer that, I think we need to see how you plan to
reference children of A. You have given us the typedef for the child
list, but how do you declare a child (or a pointer or reference to a
child) which is a member of A and a type in that list?
I don't see how this is relevant.
Maybe my OP was a bit misleading in its terminology.
<sigh>

I'll try to clarify:
Instances of A can be parents to instances of B. This
is a /run-time/ relationship. It could be achieved by
simple pointers. (In the real code, it is achieved by
each A having a list of IDs that (exclusivly) refer to
Bs. 'some_class' has some functions that hand out
references to the real objects when given the right
IDs.)
However, the important part is: Which A refers to
which B is a /run-time/ thing. That instances of A
always refer to instances of B is a /compile-time/
thing.

I haven't shown the actual run-time referencing stuff,
because I think it isn't relevant. Just assume that A
has some member templates that, given B as a template
arg, let you iterate over a list of instances of B.
The compile-time stuff needs to find out that instances
of A always refer to instances of B as children (and
that thus B should be passed to those member templates
of A).
This works for several years.
I now need to extend that compile-time mechanism so that
it finds out that instances of A refer to instances of B
/and/ instances of B2 as children and then iterates over
both child lists.
(And I need to have the very same algorithms working
with B-C and C-D relationships as well, where there's
only one child.)

What I am having problems with is that I need to change
the mechanics which, at compile time, used to find out
/if/ there's a (one) child type and, if so, iterated,
at run-time, over /the/ (one) child list into some
mechanics that, at compile-time, find out /how many/
child types there are and generates the code to, at
run-time, iterate over /all/ of those child lists.

I hope that's clearer now.
Cheers! --M

Schobi

--
Sp******@gmx.de is never read
I'm Schobi at suespammers dot org

"The sarcasm is mightier than the sword."
Eric Jarvis
Dec 1 '05 #5

P: n/a
Hendrik Schober wrote:
[snip]
I now need to extend that compile-time mechanism so that
it finds out that instances of A refer to instances of B
/and/ instances of B2 as children and then iterates over
both child lists.
(And I need to have the very same algorithms working
with B-C and C-D relationships as well, where there's
only one child.)

What I am having problems with is that I need to change
the mechanics which, at compile time, used to find out
/if/ there's a (one) child type and, if so, iterated,
at run-time, over /the/ (one) child list into some
mechanics that, at compile-time, find out /how many/
child types there are and generates the code to, at
run-time, iterate over /all/ of those child lists.

I hope that's clearer now.


Ok. You said previously that you know how to recurse the typelists
already. Could you change each parent object (A, B, and C) to have a
typelist of children rather than a simple child type, and then change
your functions to iterate over those lists? That way there is no
operational difference between having one child type and multiple, but
only A would actually have multiple types (viz. B and B2) in its list.
The remaining challenge would be to acquire the proper child object,
but that could be accomplished by adding to each parent class a
template member function that is specialized for each of its children,
e.g.,

class A
{
// ...
template <class Child> Child GetChild();
template <> B& GetChild<B >() { /* return a B */ }
template <> B2& GetChild<B2>() { /* return a B2 */ }
};

Then your algorithm would use obj.Get<ChildType>() to retrieve the
child for processing. ChildType would be determined by the current
"iteration" of the child typelist.

Cheers! --M

Dec 1 '05 #6

P: n/a
mlimber <ml*****@gmail.com> wrote:
[...]
Ok. You said previously that you know how to recurse the typelists
already. Could you change each parent object (A, B, and C) to have a
typelist of children rather than a simple child type, and then change
your functions to iterate over those lists? That way there is no
operational difference between having one child type and multiple, but
only A would actually have multiple types (viz. B and B2) in its list.
That's what I was planning. However, I didn't see a
way to iterate over typelists except by using class
templates. But I just realized I could have a function
recursivly calling itself with the tail of the list.
If the function has an overload of the tmp_nil type,
this would stop the recursion.
The remaining challenge would be to acquire the proper child object,
That's no problem. I had solved that before. :)
I just didn't know how to process TMP lists using
function templates...

Thanks for your help! I like to have things set up in
my head a few days before I start implementing them.
[...]
Cheers! --M


Schobi

--
Sp******@gmx.de is never read
I'm Schobi at suespammers dot org

"The sarcasm is mightier than the sword."
Eric Jarvis
Dec 2 '05 #7

This discussion thread is closed

Replies have been disabled for this discussion.