473,400 Members | 2,163 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,400 software developers and data experts.

Mirroring template instantiations


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<Tfrom 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<Tfor 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<Tis 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<Tinstance for every
EditorCell<Tinstance. Doing this by referencing EditorCellGui1<T>
from EditorCell<Tis 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

Oct 23 '06 #1
8 1340
"Imre" <im****@pager.huwrites:
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?

--
Cheers, Jens
Oct 23 '06 #2

Jens Theisen wrote:
"Imre" <im****@pager.huwrites:
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?
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<Tis 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<Tis
used (say, when its ctor is instantiated) for a certain T, then a
static member of EditorCellGui1<Tshould 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

Oct 24 '06 #3
Imre wrote:
[..]
Somehow I'd like to tell the compiler that whenever EditorCell<Tis
used (say, when its ctor is instantiated) for a certain T, then a
static member of EditorCellGui1<Tshould 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
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Oct 24 '06 #4

Victor Bazarov wrote:
Imre wrote:
[..]
Somehow I'd like to tell the compiler that whenever EditorCell<Tis
used (say, when its ctor is instantiated) for a certain T, then a
static member of EditorCellGui1<Tshould 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

Oct 25 '06 #5
Imre wrote:
Victor Bazarov wrote:
>Imre wrote:
>>[..]
Somehow I'd like to tell the compiler that whenever EditorCell<Tis
used (say, when its ctor is instantiated) for a certain T, then a
static member of EditorCellGui1<Tshould 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
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Oct 25 '06 #6
"Imre" <im****@pager.huwrites:
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;
--
Cheers, Jens
Oct 26 '06 #7
Jens Theisen wrote:
"Imre" <im****@pager.huwrites:
>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;
I think you're confused. What's "T" here?

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Oct 26 '06 #8

Victor Bazarov wrote:
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, PCreatorFunctionCreatorMap;
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, 1initializer;
};

template <typename T>
DerivedInitializer<Derived1<T>, T, 1Derived1<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, 2initializer;
};

template <typename T>
DerivedInitializer<Derived2<T>, T, 2Derived2<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 (<intand <floatin
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

Oct 26 '06 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Agent Mulder | last post by:
Hi group, I try to get a reference to a template. In the template, a virtual function is declared. Later in the program, I inherit from classes created by the template. So the template is the...
17
by: Jacek Dziedzic | last post by:
Hello! I have a templated class that serves as a simple vector of elements. template <typename T> class simple_vector : public math_object { // ... lots of simple_vector operations // the...
5
by: nifsmith | last post by:
Hi I am trying to learn about Queues and use templates at the same time. I have written the following code and I am getting a link error, stating "unresolved external symbol, "int__cdecl...
8
by: | last post by:
This code get's a link error (I'm guessing because the template isn't being instantiated)... // For using templates to simplify deleting items template <class T> // Returns the next ADHL in the...
1
by: Tony Johansson | last post by:
Hello Experts! I reading a book called programming with design pattern revealed by Tomasz Muldner and here I read something that I don't understand completely. Im I right if I say the...
8
by: Tony Johansson | last post by:
Hello Experts! What does this mean actually. If you have a template with a type and non-type template argument, say, like this template<typename T, int a> class Array {. . .}; then A<int,...
3
by: sks | last post by:
Hello all Is the usage of extern keyword valid for telling the compiler to NOT instantiate a template and to link it from an another binary? For example: Suppose module A's binary contains a...
2
by: Boni | last post by:
Dear all, ist it possible to have a template class or func as friend of other class: Folowing returns syntax errors template< typename T> class test{}; template< typename T> int func (Ta); ...
5
by: aryan | last post by:
Is it not allowed to have template function definition in a .cc file? Here is the scenario. The tempage function declaration is in a header file and the definition in a .cc file. The function is...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.