Mirroring template instantiations

I

Imre

Hi

I'm looking for a way to make sure that whenever a new instance of a
class template A is created, then an instance of class template B is
also created, with the same template parameters. Of course, I could do
it by referencing B<T> from A<T>, but I'd like to do it without
modifying A at all.
I'm afraid it's not possile with separate translation units, but it
might still worth asking.

Anyway, here's an example of where this could be useful.
Let's suppose that, based on a custom reflection system, we have an
object editor. It's a window, with a cell for each registered member
variables of the edited object. When constructing the editor, we create
an EditorCell<T> for each member of type T.
Let's further assume that we have multiple implementations of this
object editor, using differenet GUI libraries. We do this by
subclassing EditorCell. Say, we have EditorCellGui1<T>, and
EditorCellGui2<T>, both derived from EditorCell<T>. (We can also have
specializations of either the base or the derived classes, but that
doesn't really matter now.) We also have some config variable defining
the currently selected implementation to be used. Using this config
var, and our reflection system, we can find the corresponding subclass
of EditorCell<T>, and create a new instance of it.
So when creating a new editor cell for a member of type T, we call
EditorCell<T>::Create() (a static function), which uses the reflection
system to find a subclass (say, EditorCellGui1<T>), and calls the
subclass' Create() function, which returns a new instance.

The problem is that all these classes are templates, so they are only
instantiated if directly referenced. But EditorCellGui1<T> is never
really referenced, so it won't be instantiated, and won't be registered
into the reflection system, won't be found by EditorCell<T>::Create(),
etc.

A nice solution would be to somehow instruct the compiler to
automatically create an EditorCellGui1<T> instance for every
EditorCell<T> instance. Doing this by referencing EditorCellGui1<T>
from EditorCell<T> is quite ugly, since it needs modifying EditorCell
whenever a new gui implementation is added (and it also complicates
dependencies). So it would be better to do it in / at the subclass
(EditorCellGui1).

So, my question is, how do other people do stuff like this? Any
workarounds, alternative designs, suggestions, whatever?

Thanks,

Imre
 
J

Jens Theisen

Imre said:
So, my question is, how do other people do stuff like this? Any
workarounds, alternative designs, suggestions, whatever?

Unfortunately I'm not understanding what you're getting it, which is
in part due to confused terminology I think. Instantiation of a
template happens, for example, if I have the expression
EditorCell<T>::Create somewhere rather than just EditorCell<T>. This
can't cause any registration though, since it won't instantiate any
members unless they are also referenced (eg by taking their
address). So what exactly do you mean here? What does the
registration?
 
I

Imre

Jens said:
Unfortunately I'm not understanding what you're getting it, which is
in part due to confused terminology I think. Instantiation of a
template happens, for example, if I have the expression
EditorCell<T>::Create somewhere rather than just EditorCell<T>. This
can't cause any registration though, since it won't instantiate any
members unless they are also referenced (eg by taking their
address). So what exactly do you mean here? What does the
registration?

Well, I was under the (false) impression that if any part of a class
template is referenced / instantiated, then all static members of that
class template will also be instantiated. This is not so.

Anyway, let me rephrase the question (sorry if it won't be much
clearer, english is not my native language).

In the end, I'd like to find an appropriate subclass of EditorCell<T>,
based on some runtime value. If it weren't a template, it would be
easy; all subclasses could register themselves at startup (from the
ctor of a static member), as subclasses of EditorCell. Later I could
easily pick one of them.

If these are class templates, then this is not so easy, as no one
references those subclasses directly, so they are not instantiated at
all. Only the base, EditorCell<T> is referenced, and its Create()
should return a new instance of the right subclass, which is then used
through virtual function calls. (As far as I know, virtual functions
are always explicitly instantiated. I'm sure it works this way on many
compilers, but I don't know if it's standard or compiler-dependent
behavior.)

Somehow I'd like to tell the compiler that whenever EditorCell<T> is
used (say, when its ctor is instantiated) for a certain T, then a
static member of EditorCellGui1<T> should also be instantiated
automatically. The ctor of that static member could register the
subclass at the base.

So, if there's an EditorCell<int> (ctor) reference, then generate an
EditorCellGui1<int>::staticInitializer instance as well. If there's
EditorCell<float>, generate EditorCellGui1<float>::staticInitializer,
etc.

And I'd like to do this without modifying the base class at all (after
all, that's the whole point of the registration stuff). So I'd like to
do something at the site of the subclass implementation, that results
in this behavior.

Is it any clearer now?

Imre
 
V

Victor Bazarov

Imre said:
[..]
Somehow I'd like to tell the compiler that whenever EditorCell<T> is
used (say, when its ctor is instantiated) for a certain T, then a
static member of EditorCellGui1<T> should also be instantiated
automatically. The ctor of that static member could register the
subclass at the base. [..]

You could simply take the address of the static member of EditorCellGui1
in a constructor of EditorCell which will cause the static member to be
instantiated. You don't have to retain the address you take (if you do
not need it).

V
 
I

Imre

Victor said:
Imre said:
[..]
Somehow I'd like to tell the compiler that whenever EditorCell<T> is
used (say, when its ctor is instantiated) for a certain T, then a
static member of EditorCellGui1<T> should also be instantiated
automatically. The ctor of that static member could register the
subclass at the base. [..]

You could simply take the address of the static member of EditorCellGui1
in a constructor of EditorCell which will cause the static member to be
instantiated. You don't have to retain the address you take (if you do
not need it).

This is quite similar to my idea (calling a dummy function of the
static member). The problem is still that I need to modify the base
class whenever adding a new subclass. I'd like to avoid that if
possible.

Imre
 
V

Victor Bazarov

Imre said:
Victor said:
Imre said:
[..]
Somehow I'd like to tell the compiler that whenever EditorCell<T> is
used (say, when its ctor is instantiated) for a certain T, then a
static member of EditorCellGui1<T> should also be instantiated
automatically. The ctor of that static member could register the
subclass at the base. [..]

You could simply take the address of the static member of
EditorCellGui1 in a constructor of EditorCell which will cause the
static member to be instantiated. You don't have to retain the
address you take (if you do not need it).

This is quite similar to my idea (calling a dummy function of the
static member). The problem is still that I need to modify the base
class whenever adding a new subclass. I'd like to avoid that if
possible.

Well, I've re-read your original post and can't claim full understanding
of the design intent, sorry. Perhaps a complete program that does what
you describe (even if it fails to compile or link) would be in order.

You modify something when adding a subclass, you might as well modify
something else... For example, the "config variable" that your class
uses to find the proper "implemenation" to be instantiated. If you are
adding another implementation, then the 'config' has to know about it,
no? So, you need to make your "config" thing aware of the new derived
class, right? Wouldn't that be the place where the derived class static
object is instantiated?

If the "config" is not the compile-time mechanism, then you cannot use
compile-time polymorphism with it. You need to opt for the run-time one
with virtual functions and so on.

V
 
J

Jens Theisen

Imre said:
This is quite similar to my idea (calling a dummy function of the
static member). The problem is still that I need to modify the base
class whenever adding a new subclass. I'd like to avoid that if
possible.

You can reference it anywhere you like, for example along the
definition of EditorCellGui1 at global scope:

InitialiserType const* const dummy = &EditorCellGui1< T >::initialiser;
 
V

Victor Bazarov

Jens said:
You can reference it anywhere you like, for example along the
definition of EditorCellGui1 at global scope:

InitialiserType const* const dummy = &EditorCellGui1< T

I think you're confused. What's "T" here?

V
 
I

Imre

Victor said:
Well, I've re-read your original post and can't claim full understanding
of the design intent, sorry. Perhaps a complete program that does what
you describe (even if it fails to compile or link) would be in order.

All right, here's a complete (a bit long) example:

// --- Base.h ---

#ifndef Base_H
#define Base_H

#include <map>
#include <iostream>

template <typename T>
class Base
{
public:
typedef Base* (*PCreatorFunction)();

static void RegisterCreator(int id, PCreatorFunction f)
{
creators[id] = f;
}
static Base* Create(int id)
{
Derived1<T>::Dummy();
Derived2<T>::Dummy();

PCreatorFunction cf = creators[id];
return cf();
}

virtual void F() { std::cout << "Base::F()"; }

protected:
typedef std::map<int, PCreatorFunction> CreatorMap;
static CreatorMap creators;
};

template <typename T>
typename Base<T>::CreatorMap Base<T>::creators;


template <typename D, typename T, int id>
struct DerivedInitializer
{
DerivedInitializer()
{
Base<T>::RegisterCreator(id, &D::Create);
}
void Dummy() {}
};

#endif

// --- Derived1.h ---

#ifndef Derived1_H
#define Derived1_H

#include "Base.h"

template <typename T>
class Derived1:
public Base<T>
{
public:
static void Dummy() { initializer.Dummy(); }
static Base<T>* Create() { return new Derived1<T>; }

virtual void F() { std::cout << "Derived1::F()"; }

protected:
static DerivedInitializer<Derived1<T>, T, 1> initializer;
};

template <typename T>
DerivedInitializer<Derived1<T>, T, 1> Derived1<T>::initializer;

#endif

// --- Derived2.h ---

#ifndef Derived2_H
#define Derived2_H

#include "Base.h"

template <typename T>
class Derived2:
public Base<T>
{
public:
static void Dummy() { initializer.Dummy(); }
static Base<T>* Create() { return new Derived2<T>; }

virtual void F() { std::cout << "Derived2::F()"; }

protected:
static DerivedInitializer<Derived2<T>, T, 2> initializer;
};

template <typename T>
DerivedInitializer<Derived2<T>, T, 2> Derived2<T>::initializer;

#endif

// --- main.cpp ---

#include "Base.h"
#include "Derived1.h"
#include "Derived2.h"

int main(int argc, char *argv[])
{
int id;

id = 1;

Base<int>* bi1 = Base<int>::Create(id);
bi1->F(); // Derived1
Base<float>* bf1 = Base<float>::Create(id);
bf1->F(); // Derived1

id = 2;

Base<int>* bi2 = Base<int>::Create(id);
bi2->F(); // Derived2

return 0;
}

// ---

This does work, but the Dummy() calls in Base::Create are ugly, because
that list needs to be extended whenever a new subclass (say,
Derived3<T>: public Base<T>) is added. The system cannot be cleanly
extended without modifying existing code.
If these were normal, non-template classes, then this would not be
necessary, new subclasses could be added without modifying Base.

As Jens suggested, I could place those Dummy() calls (or any other
references that force the instantiation of the derived initializer)
somewhere else, but that wouldn't really solve the problem. Actually,
if those are not in Base, then things are even worse, as instead of
referencing DerivedX<T>, I need to reference DerivedX<int>,
DerivedX<float>, etc. separately. And if a new Derived is added, I need
to revisit all the places where such references are written, and extend
the list.
(Note that Base is used with implicit instantiation. Having the client
to explicitly instantiate the subclasses is.. at least strange.)

Also note that the information about what instances of, say,
Derived1::initializer should be created, are almost there. The compiler
knows what instances of Base::Create are created (<int> and <float> in
the above example). I'd like to tell it to create the same instances of
the subclass initializers. Actually that's what the Dummy() calls do,
it's just that they are at a very wrong place.

Maybe I'm worrying too much over this; after all, adding a new line to
Base::Create for each subclass isn't that much. But still, modifying
existing code because of adding a new subclass somehow feels wrong.
Also, if this pattern works for non-templates, it should work for
templates as well.
You modify something when adding a subclass, you might as well modify
something else... For example, the "config variable" that your class
uses to find the proper "implemenation" to be instantiated. If you are
adding another implementation, then the 'config' has to know about it,
no?

Not necessarily, see the example. The config var (called id in the
example) is a simpe integer, and all subclasses are assigned an integer
identifying them. When using the Base as a factory, we just give it a
subclass id, and it can find the right one -- as long as subclasses are
properly registered at startup.

Anyway, thanks for all the answers.

Imre
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,906
Latest member
SkinfixSkintag

Latest Threads

Top