Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

virtual template functions

5 views
Skip to first unread message

Thomas Mang

unread,
Sep 21, 2002, 2:13:10 PM9/21/02
to
Hi everybody,

Although a template class can have virtual functions, a class (wether
it is a template class or not) cannot have virtual template functions.

My wish:

Please implement virtual template functions in the next standard. I
would no doubt pay the price for (possibly) increased compile time and
maybe slower function-call time, so requirements for compiler writers
to implement it would not have been too high.


regards,

Thomas

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

James Russell Kuyper Jr.

unread,
Sep 21, 2002, 10:28:02 PM9/21/02
to
Thomas Mang wrote:
>
> Hi everybody,
>
> Although a template class can have virtual functions, a class (wether
> it is a template class or not) cannot have virtual template functions.
>
> My wish:
>
> Please implement virtual template functions in the next standard. I
> would no doubt pay the price for (possibly) increased compile time and
> maybe slower function-call time, so requirements for compiler writers
> to implement it would not have been too high.

With the typical implementation of virtual functions, you need a
seperate entry in the vtable for each such function. A templated member
function defines an infinite family of related functions. There's
probably some clever way to get around this, but without major
modifications, the existing methods for implementing virtual functions
would require a vtable of infinite length if it were templated. Which is
slightly problematic. :-)

Thomas Mang

unread,
Sep 23, 2002, 1:18:01 AM9/23/02
to
kuy...@wizard.net ("James Russell Kuyper Jr.") wrote in message news:<3D8CD438...@wizard.net>...

> Thomas Mang wrote:
> >
> > Hi everybody,
> >
> > Although a template class can have virtual functions, a class (wether
> > it is a template class or not) cannot have virtual template functions.
> >
> > My wish:
> >
> > Please implement virtual template functions in the next standard. I
> > would no doubt pay the price for (possibly) increased compile time and
> > maybe slower function-call time, so requirements for compiler writers
> > to implement it would not have been too high.
>
> With the typical implementation of virtual functions, you need a
> seperate entry in the vtable for each such function. A templated member
> function defines an infinite family of related functions. There's
> probably some clever way to get around this, but without major
> modifications, the existing methods for implementing virtual functions
> would require a vtable of infinite length if it were templated. Which is
> slightly problematic. :-)

I know it isn't without any problems :-).

That's why I explicitly mentioned that the runtime cost / compile time
cost should be allowed to be higher than for "normal" template
functions.

I have written in the c++-moderated newsgroup two threads about
virtual template function implementations(one suggests to implement in
the vtable a single pointer to another vtable for all the virtual
template functions. This costs one additional level of indirection.
The other is a workaround using today's C++ - features. Although
really ugly to write, it works and follows a mechanically
implementable scheme, one compiler writers could adopt.)

After all, I do not consider decreased performance to be a problem.
Taking into account where computers are today compared to where they
had been some years ago (and didn't you use virtual functions than
too?), a performance loss by a factor of, say, 5 - 10 or so compared
to "normal virtual functions" shouldn't hurt that much. Especially
because I think the program won't, in general, spent most of the time
in virtual template functions.

best regards,

Thomas

Francis Glassborow

unread,
Sep 23, 2002, 1:41:18 AM9/23/02
to
In article <3D8CD438...@wizard.net>, James Russell Kuyper Jr.
<kuy...@wizard.net> writes

>> Please implement virtual template functions in the next standard. I
>> would no doubt pay the price for (possibly) increased compile time and
>> maybe slower function-call time, so requirements for compiler writers
>> to implement it would not have been too high.
>
>With the typical implementation of virtual functions, you need a
>seperate entry in the vtable for each such function. A templated member
>function defines an infinite family of related functions. There's
>probably some clever way to get around this, but without major
>modifications, the existing methods for implementing virtual functions
>would require a vtable of infinite length if it were templated. Which is
>slightly problematic. :-)

And it gets nastier when we throw in two virtual function templates and
multiple inheritance. We are trying to find ways to make separate
compilation of templates work (decreasing the coupling between point of
definition and point of use). Supporting virtual function templates
would seem to by flying in the opposite direction.

I would oppose anything that made templates more complicated to either
implement or use than they already are. Some increased implementation
cost might be acceptable for radical simplification of use but that is
as far as I would bend.


--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

James Kanze

unread,
Sep 23, 2002, 10:37:53 AM9/23/02
to
francis.g...@ntlworld.com (Francis Glassborow) wrote in message
news:<NvmG$fF0Sa...@robinton.demon.co.uk>...

> In article <3D8CD438...@wizard.net>, James Russell Kuyper Jr.
> <kuy...@wizard.net> writes
> >> Please implement virtual template functions in the next standard. I
> >> would no doubt pay the price for (possibly) increased compile time
> >> and maybe slower function-call time, so requirements for compiler
> >> writers to implement it would not have been too high.

> >With the typical implementation of virtual functions, you need a
> >seperate entry in the vtable for each such function. A templated
> >member function defines an infinite family of related
> >functions. There's probably some clever way to get around this, but
> >without major modifications, the existing methods for implementing
> >virtual functions would require a vtable of infinite length if it
> >were templated. Which is slightly problematic. :-)

> And it gets nastier when we throw in two virtual function templates
> and multiple inheritance. We are trying to find ways to make separate
> compilation of templates work (decreasing the coupling between point
> of definition and point of use). Supporting virtual function templates
> would seem to by flying in the opposite direction.

> I would oppose anything that made templates more complicated to either
> implement or use than they already are. Some increased implementation
> cost might be acceptable for radical simplification of use but that is
> as far as I would bend.

Realistically, too, although the standard says nothing about it, you'd
want it to work with dynamically loaded objects.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

James Russell Kuyper Jr.

unread,
Sep 23, 2002, 10:37:54 AM9/23/02
to
Thomas Mang wrote:
>
> kuy...@wizard.net ("James Russell Kuyper Jr.") wrote in message news:<3D8CD438...@wizard.net>...
....

> > seperate entry in the vtable for each such function. A templated member
> > function defines an infinite family of related functions. There's
> > probably some clever way to get around this, but without major
> > modifications, the existing methods for implementing virtual functions
> > would require a vtable of infinite length if it were templated. Which is
> > slightly problematic. :-)
>
> I know it isn't without any problems :-).
>
> That's why I explicitly mentioned that the runtime cost / compile time
> cost should be allowed to be higher than for "normal" template
> functions.
>
> I have written in the c++-moderated newsgroup two threads about
> virtual template function implementations(one suggests to implement in
> the vtable a single pointer to another vtable for all the virtual
> template functions. This costs one additional level of indirection.

But how do you index into that second table? There's an infinite number
of possible indices into that table, which seems to mean that the second
table must be infinitely long. I'm not saying it can't be done - I've
seen a lot of problems I thought were insoluble handled efficiently by a
clever approach. However, your description isn't sufficiently specific
for me to understand how it bypasses the infinity problem.

> The other is a workaround using today's C++ - features. Although
> really ugly to write, it works and follows a mechanically
> implementable scheme, one compiler writers could adopt.)
>
> After all, I do not consider decreased performance to be a problem.
> Taking into account where computers are today compared to where they
> had been some years ago (and didn't you use virtual functions than
> too?), a performance loss by a factor of, say, 5 - 10 or so compared
> to "normal virtual functions" shouldn't hurt that much. Especially

Off the top of my head, the simplest approach I can think of that would
work is for the program to maintain a list of all the template argument
combinations used in any instantiation of that virtual template member
function. That list couldn't reach final form until link phase. At
runtime, every use of that member function would involve a search
through that list for a matching entry. This would be very inefficient
approach; it would be a lot more than 5-10 times slower than normal
virtual function access.

Hyman Rosen

unread,
Sep 23, 2002, 10:38:40 AM9/23/02
to
Thomas Mang wrote:
> Please implement virtual template functions in the next standard.

This is essentially impossible, given dynamic linking.

Anthony Williams

unread,
Sep 23, 2002, 12:19:02 PM9/23/02
to
kuy...@wizard.net ("James Russell Kuyper Jr.") writes:

> Thomas Mang wrote:
> > Please implement virtual template functions in the next standard. I
> > would no doubt pay the price for (possibly) increased compile time and
> > maybe slower function-call time, so requirements for compiler writers
> > to implement it would not have been too high.
>
> With the typical implementation of virtual functions, you need a
> seperate entry in the vtable for each such function. A templated member
> function defines an infinite family of related functions. There's
> probably some clever way to get around this, but without major
> modifications, the existing methods for implementing virtual functions
> would require a vtable of infinite length if it were templated. Which is
> slightly problematic. :-)

I proposed an outline implementation in a post to comp.lang.c++.moderated
about a year ago (link redirects to google groups):

http://makeashorterlink.com/?R12F450E1

The "I know how to instantiate Base::func<T1,T2>()" type entries could be
handled by requiring such templates to be exported, in order to avoid the
additional export-like mechanism described in the original article.

Anthony

Anthony Williams

unread,
Sep 23, 2002, 12:22:32 PM9/23/02
to
hyr...@mail.com (Hyman Rosen) writes:

> Thomas Mang wrote:
> > Please implement virtual template functions in the next standard.
>
> This is essentially impossible, given dynamic linking.

Templates and dynamic linking just don't go well together, whether or not you
allow virtual functions to be templates.

Anthony

Francis Glassborow

unread,
Sep 23, 2002, 2:15:36 PM9/23/02
to
In article <3D8EF5B4...@wizard.net>, James Russell Kuyper Jr.
<kuy...@wizard.net> writes

>Off the top of my head, the simplest approach I can think of that would
>work is for the program to maintain a list of all the template argument
>combinations used in any instantiation of that virtual template member
>function. That list couldn't reach final form until link phase. At
>runtime, every use of that member function would involve a search
>through that list for a matching entry. This would be very inefficient
>approach; it would be a lot more than 5-10 times slower than normal
>virtual function access.

And I think trying to get it to work with DLLs and the equivalent would
be more than a little problematic.


--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---

Hyman Rosen

unread,
Sep 23, 2002, 2:16:38 PM9/23/02
to
Anthony Williams wrote:
> Templates and dynamic linking just don't go well together,
> whether or not you allow virtual functions to be templates.

Do you have an example that illustrates what you mean?
I'm not aware of any such problems.

Hyman Rosen

unread,
Sep 23, 2002, 4:26:36 PM9/23/02
to
James Russell Kuyper Jr. wrote:
> That list couldn't reach final form until link phase.

And remember that many programs use dynamic linking,
so "link phase" also includes "at runtime".

Anthony Williams

unread,
Sep 24, 2002, 8:25:30 AM9/24/02
to
hyr...@mail.com (Hyman Rosen) writes:

> Anthony Williams wrote:
> > Templates and dynamic linking just don't go well together,
> > whether or not you allow virtual functions to be templates.
>
> Do you have an example that illustrates what you mean?
> I'm not aware of any such problems.

Assuming that all the dynamically-linked modules are written in C++, as well
as the main program, the only way to know that foo<T> has been instantiated
for each T used in a given dynamically-linked module is to include the
instantiation in that module. However, each static data member, and each
member function must have a single address across the whole program, including
the dynamically-linked modules. Therefore, if foo<T> is used in two modules
with the same T, you have an error, unless (a) you have some mechanism of
selecting which of the two instantiations to use, or (b) you know in advance
the set of all T for which foo<T> will be instantiated, and inhibit
instantiation in all-but-one module.

A similar restriction then applies to virtual functions that are templates
(assuming it is allowed) if they are to be used across dynamic module
boundaries --- you must know in advance which instantiations of
base::func<T>() will be used, so if one module calls base::func<T>(), there is
a corresponding derived::func<T>() to be called, even if derived is defined in
a different module.

Anthony

James Kanze

unread,
Sep 25, 2002, 11:33:30 AM9/25/02
to
ant...@nortelnetworks.com ("Anthony Williams") wrote in message
news:<adm7hk...@nortelnetworks.com>...
> hyr...@mail.com (Hyman Rosen) writes:

> > Anthony Williams wrote:
> > > Templates and dynamic linking just don't go well together,
> > > whether or not you allow virtual functions to be templates.

> > Do you have an example that illustrates what you mean? I'm not
> > aware of any such problems.

> Assuming that all the dynamically-linked modules are written in C++,
> as well as the main program, the only way to know that foo<T> has been
> instantiated for each T used in a given dynamically-linked module is
> to include the instantiation in that module.

But that's true for any function, not just template instantiations.
What about the static variables used by malloc and free, for example?
You certainly can't have multiple copies just because two different
dynamically loaded objects use malloc.

> However, each static data member, and each member function must have a
> single address across the whole program, including the
> dynamically-linked modules. Therefore, if foo<T> is used in two
> modules with the same T, you have an error, unless (a) you have some
> mechanism of selecting which of the two instantiations to use, or (b)
> you know in advance the set of all T for which foo<T> will be
> instantiated, and inhibit instantiation in all-but-one module.

So what else is new? A dynamic linker which didn't do this would be
useless. You couldn't allocate memory from one dynamically linked
object, and free it in another, for example. (My experience with
dynamically linked objects is pretty limited, but I do know that at
this works, at least with the dynamic linker under Sparc Solaris.)

> A similar restriction then applies to virtual functions that are
> templates (assuming it is allowed) if they are to be used across
> dynamic module boundaries --- you must know in advance which
> instantiations of base::func<T>() will be used, so if one module calls
> base::func<T>(), there is a corresponding derived::func<T>() to be
> called, even if derived is defined in a different module.

The problem with templated virtual functions is more complicated, since
you presumably don't even know the size of the vtable until the last
dynamically linked object has been incorporated. I think it is doable,
but it could require some extensions to the current dynamic linking
model.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

---

Hyman Rosen

unread,
Sep 25, 2002, 12:07:39 PM9/25/02
to
Anthony Williams wrote:
(trimmed)

> the only way to know that foo<T> has been instantiated
> is to include the instantiation in that module.
> you have an error, unless you have some mechanism of

> selecting which of the two instantiations to use

But this is no different than the model used by many compilers
for normal template compilation and linking. Since it's a
violation of the ODR for instantiations to be different in
different modules, the dynamic linker just has to adjust
references in the loaded module to point to the ones already
present in the program.

This wouldn't be enough for me to say that templates and
dynamic linking don't mix, but maybe my standards are lower
(higher?).

Ron Natalie

unread,
Sep 25, 2002, 12:55:58 PM9/25/02
to

"Hyman Rosen" <hyr...@mail.com> wrote in message news:10328973...@master.nyc.kbcfp.com...

> But this is no different than the model used by many compilers
> for normal template compilation and linking.

The difference is that the construction of the object needs to know
all the places where a virtual template member might have been
expanded. A non-virtual template member (or non-member) only
requires synchronization against other template expansions of
the same template. Of course this is surmoutable (just more involve
than the common vtable method people are currently union).

The real show stopper is what happens when you OVERRIDE the
virtual method. It is very hard to intuit at compile time how to expand
the template in the derived class.

struct Base {
virtual ~Base();
template <typename T> virtual void VMember(T);
};

Base* ReturnsSomethingDerivedFromBase();

Base* bp = ReturnsSomethingDerivedFromBase();

bp->VMember(4);

How does the compiler know to expand Derived::VMember so that
it overrides Base::VMember<int>?

Hyman Rosen

unread,
Sep 25, 2002, 12:56:26 PM9/25/02
to
James Kanze wrote:
> The problem with templated virtual functions is more complicated

The problem is that you don't know until link time
which instantiations you need. With dynamic linking,
this means that you have to generate instantiations
at runtime!

Base.h:
struct Base { template<class T> virtual void f() { } };
void f(Base *);

Base.cpp:
void f(Base *p) { p->f<int>(); }

Derived.h:
#include "Base.h"
struct Derived : Base { template<class T> void f() { } };

Test.cpp:
#include "Derived.h"
int main() { Derived d; f(&d); }

A program which includes Base.cpp must indicate in some
fashion that it requires instantiations of f<int> for all
classes derived from Base which override f<>. If such a
class is dynamically loaded, then this instantiation must
be generated at that time; it cannot be done sooner, since
we do not know which instantiations will be needed.

Of course, once we overcome this obstacle, we can finally
implement those much-desired templated catch clauses :-)

Hyman Rosen

unread,
Sep 25, 2002, 1:25:18 PM9/25/02
to
Ron Natalie wrote:
> The real show stopper

I understand the problem with virtual member template methods.
I was responding to the claim that templates and dynamic linking
don't go well together even wihout them.

Alf P. Steinbach

unread,
Sep 25, 2002, 1:31:18 PM9/25/02
to
On Wed, 25 Sep 2002 16:56:26 +0000 (UTC), hyr...@mail.com (Hyman Rosen) wrote:

>...


>Base.h:
>struct Base { template<class T> virtual void f() { } };
>void f(Base *);
>
>Base.cpp:
>void f(Base *p) { p->f<int>(); }
>
>Derived.h:
>#include "Base.h"
>struct Derived : Base { template<class T> void f() { } };
>
>Test.cpp:
>#include "Derived.h"
>int main() { Derived d; f(&d); }
>
>A program which includes Base.cpp must indicate in some
>fashion that it requires instantiations of f<int> for all
>classes derived from Base which override f<>. If such a
>class is dynamically loaded, then this instantiation must
>be generated at that time; it cannot be done sooner, since
>we do not know which instantiations will be needed.
>
>Of course, once we overcome this obstacle, we can finally
>implement those much-desired templated catch clauses :-)

While a templated catch clause (uuuuuurrgh! what a concept!)
cannot in principle have the type information until runtime,
and then from an open-ended set of types (up to the number of
distinct types appearing in throws, in statically or dynamically
linked code), in principle the type information required above
seem to be available at compile time and so can be passed to the
linker. If I'm wrong about that, which I very well might be,
please someone explain that, since I'm interested in the
foundations here. Not that I'm supporting the scheme.

The real problem, as I see it, is that an override of f<>
might use operations that are not availabe for type int. For
static linking this could also, presumably, be resolved, although
the information the compiler would have to gather and the linker
would have to consider would be very complex, but for dynamic
linking we'd then be out in la-la land, a place where the Liskov
substitution principle does not hold. However, since I've not
followed this debate closely, perhaps it's already been discussed
and resolved, in some way (e.g. by restrictions on the scheme)?

If not, then the idea of virtual template functions seems to
require some kind of *restriction* on template args, e.g. as
in Eiffel, at least if dynamic linking is still to be supported.

C++ templates as they are today are then simply too powerful.

Perhaps the old idea of "notions" (pure syntactic level
conformance) could help, but it seems like building a second, or
would it be third?, new small sublanguage inside C++.

Cheers,

- Alf

Hyman Rosen

unread,
Sep 25, 2002, 3:05:36 PM9/25/02
to
Alf P. Steinbach wrote:
> in principle the type information required above
> seem to be available at compile time and so can be passed to the
> linker. If I'm wrong about that, which I very well might be,
> please someone explain that, since I'm interested in the
> foundations here.

If at one point in a program I access a virtual template
method through a pointer or reference to a base class, I
must require that all derived classes of this base class
which override this method must have the method instantiated
for whichever types the access through the base used.

In my example, I accessed base_p->f<int>, so all derived
classes which override f must instantiate their f<int> and
add it to whatever virtual table scheme we're using for
this. The reason is that I might pass a pointer to one of
these derived objects to my function, and for virtual
overriding to work, I need the derived instantiation.

Notice that this is a whole-program task, because until all
the pieces are brought together the compiler cannot know
which methods in derived classes need to be instantiated on
the above basis. Normally, such whole program tasks are done
at link-time, but dynamic linking pushes that to runtime.
That is, suppose that the function
void g(Base *p) { p->f<double>(); }
was loaded from a dynamic library. All of a sudden, we realize
that we need f<double> instantiated for all derived classes of
Base which override f<>. What do we do?

Alf P. Steinbach

unread,
Sep 25, 2002, 5:15:59 PM9/25/02
to

Thanks for that.

As to what do we do (not that I'm supporting the scheme (see
previous posting for one reason why)), perhaps just not support
in the language dynamic linking where type information isn't
available at compile time. After all, it isn't supported
today, AFAIK.

I don't know the details about Unix dynamic linking, but in
Windows there are three options:

1 Dynamic linking performed automatically at program *load
time*. This can be and is usually fully type-checked (except
if some scoundrel replaces that DLL with something else ;-) ).
The type-checking is static, at static link time.

2 Deferred dynamic linking, which is just as the above except
the linker inserts stubs for every function imported from the
DLL, and the DLL is transparently loaded the first time one
stub is called. In case of load error, not so transparent.

3 Run-time explicit dynamic loading, no real linking involved,
in which case there is *no* type checking; it's the
programmer's full responsibility to call API functions to
obtain function addresses from the loaded DLL, and to
ensure the so obtained functions have correct sigs etc.

Wrt. type checking cases 1 and 2 are equivalent to ordinary full
static linking, except in the "scoundrel" case as noted above.

Case 3 is more difficult, and if I understand it correctly, where
your argument applies, but AFAIK case 3 isn't supported today. Not
that cases 1 and 2 are explicitly supported either, if we ignore the
few comments about initialization order in the standard. But cases
1 and 2 are essentially, type-checking wise, same as static linking.

So, my comment still stands, I think, namely, the type information
required in the earlier posting's example code seems to be available
at compile time and so can be passed to the linker???

Cheers,

- Alf

Hyman Rosen

unread,
Sep 25, 2002, 6:27:32 PM9/25/02
to
Alf P. Steinbach wrote:
> I don't know the details about Unix dynamic linking, but in
> Windows there are three options:

This problem is completely independent of platform.
It has nothing to do with type checking at link time.

In most implementations of C++, virtual methods of
class templates are always instantiated whenever the
template is instantiated, unlike non-virtual methods
which are only instantiated if called. 14.7.1/9 talks
about this. The reason is that when the class is
instantiated, the compiler doesn't know whether the
virtual function will be called from some other point,
and must therefore provide a pointer to the function
in the virtual table just in case.

Exactly the same situation applies to virtual member
function templates, but here it is impossible to
instantiate all the cases, since there are an infinite
number. The only possibility of success is if the
compiler can know which instances it will need, and it
can't know that if new functions can appear at runtime.

Hyman Rosen

unread,
Sep 26, 2002, 11:45:29 AM9/26/02
to
Hyman Rosen wrote:
> This problem is completely independent of platform.
> It has nothing to do with type checking at link time.

If virtual member function templates are ever implemented,
it is likely that they will require a special kind of vtable
in which functions will be looked up by name rather than
positional index. Then it will be possible to detect that a
derived class lacks a needed specialization, so we will at
least be able to generate an error at runtime. You could
then go to your build system and issue the magic utterances
which would cause the needed instantiations to be generated
and incorporated into the program or library.

Anthony Williams

unread,
Sep 26, 2002, 12:49:37 PM9/26/02
to
ka...@gabi-soft.de (James Kanze) writes:

> ant...@nortelnetworks.com ("Anthony Williams") wrote in message
> news:<adm7hk...@nortelnetworks.com>...
> > hyr...@mail.com (Hyman Rosen) writes:
>
> > > Anthony Williams wrote:
> > > > Templates and dynamic linking just don't go well together,
> > > > whether or not you allow virtual functions to be templates.
>
> > > Do you have an example that illustrates what you mean? I'm not
> > > aware of any such problems.
>
> > Assuming that all the dynamically-linked modules are written in C++,
> > as well as the main program, the only way to know that foo<T> has been
> > instantiated for each T used in a given dynamically-linked module is
> > to include the instantiation in that module.
>
> But that's true for any function, not just template instantiations.
> What about the static variables used by malloc and free, for example?
> You certainly can't have multiple copies just because two different
> dynamically loaded objects use malloc.

Most functions can be reliably listed as external symbols, to be fixed up by
the dynamic linker. Indeed I would expect malloc to be in an OS-specific
dynamic module, so there is only one instance of malloc, and no clash occurs.

The problem with templates is that if my DLL uses foo<MyType> then I had
better included it in the DLL, unless I know that another module is going to
provide the definition. Unless I place restrictions on the T in
foo<T>, I cannot know this, so I must include the definition in my DLL.

> > However, each static data member, and each member function must have a
> > single address across the whole program, including the
> > dynamically-linked modules. Therefore, if foo<T> is used in two
> > modules with the same T, you have an error, unless (a) you have some
> > mechanism of selecting which of the two instantiations to use, or (b)
> > you know in advance the set of all T for which foo<T> will be
> > instantiated, and inhibit instantiation in all-but-one module.
>
> So what else is new? A dynamic linker which didn't do this would be
> useless. You couldn't allocate memory from one dynamically linked
> object, and free it in another, for example. (My experience with
> dynamically linked objects is pretty limited, but I do know that at
> this works, at least with the dynamic linker under Sparc Solaris.)

Again, with your example, malloc is a C runtime function, included in libc.so
on Solaris, and msvcrt.dll (or similar) on windows. Since there is only one
instance of malloc and its associated static data, you can allocate data in
one DLL and free it in another. Indeed, with MSVC you have the option of
linking each DLL against a static copy of the C runtime, in which case you
_cannot_ allocate memory in one DLL and free it in another, as each DLL uses
its own static data.

On win32, when you import a symbol you have to specify which DLL it comes
from. Therefore dll1.foo<T> and dll2.foo<T> are distinct symbols, even if the
T is the same. Therefore with the tools I know to be available, it is _not_
possible for the dynamic linker to eliminate one of the instantiations. Of
course, there may be tools I don't know about.

On Solaris (and probably other Unices), the whole program occupies a single
namespace, so if a DLL has an external symbol, this is matched against an
instance of this symbol in the whole program (including loaded DLLs), and if
the main program has an external symbol, this is matched against any symbol
with the same name in any DLL. With this mechanism it is simpler to eliminate
duplicates.

> > A similar restriction then applies to virtual functions that are
> > templates (assuming it is allowed) if they are to be used across
> > dynamic module boundaries --- you must know in advance which
> > instantiations of base::func<T>() will be used, so if one module calls
> > base::func<T>(), there is a corresponding derived::func<T>() to be
> > called, even if derived is defined in a different module.
>
> The problem with templated virtual functions is more complicated, since
> you presumably don't even know the size of the vtable until the last
> dynamically linked object has been incorporated. I think it is doable,
> but it could require some extensions to the current dynamic linking
> model.

I would be quite happy to say that if you use a templated virtual function,
don't expect to be able to call it across DLL boundaries. However, I can also
see that doing precisely that can be useful. If you call baseRef.func<T> from
any DLL, this requires that it is present in the vtable for the base type
_and_ all the derived types. I can see no way of doing this with dynamic
linking short of including the compiler in the runtime for the program, along
with the program source code, or restricting T in some fashion, so that the
derived types know which instantations are required.

I actually think the whole issue is _very_ much like export, and as I said in
another post, I would be quite happy to require that templated virtual
functions are also exported.

The dependency chain requires that the derived vtables are finalised after the
base vtable, which can only happen once all the call points have been
established. For static linking, this is possible with current linker
technology and a pre-linker, as all the information is available. For dynamic
linking I am not sure it _can_ be made to work without restricting T, but I
don't think this is a big problem.

Anthony

Anthony Williams

unread,
Sep 26, 2002, 12:49:47 PM9/26/02
to
hyr...@mail.com (Hyman Rosen) writes:

> Anthony Williams wrote:
> (trimmed)
> > the only way to know that foo<T> has been instantiated
> > is to include the instantiation in that module.
> > you have an error, unless you have some mechanism of
> > selecting which of the two instantiations to use
>
> But this is no different than the model used by many compilers
> for normal template compilation and linking. Since it's a
> violation of the ODR for instantiations to be different in
> different modules, the dynamic linker just has to adjust
> references in the loaded module to point to the ones already
> present in the program.

As I just discussed in another post, on Unix this is OK, as all symbols occupy
the same "namespace", and multiple definitions are handled by the dynamic
loader in a documented fashion. On win32, when you import a symbol, you have
to specify which DLL it comes from. Therefore foo<T> in DLL1 is distinct from
foo<T> in DLL2. It would be quite a lot of work for the runtime library to
examine the exported symbol list of each DLL and check for clashes with the
exported symbols from all the other DLLs, and relink all the imports against a
single one.



> This wouldn't be enough for me to say that templates and
> dynamic linking don't mix, but maybe my standards are lower
> (higher?).

If you have a system where it works, then that is good. However, things aren't
as straight-forward on every platform that supports dynamic linking.

The Standard is silent on dynamic linking. IMHO, if it is going to be used as
an argument for or against a feature, then it should be specified in the
Standard what requirements are placed on a system that does support dynamic
linking, and the new feature can then be discussed in the context of those
requirements.

Indeed, dynamic linking is a big topic unto itself --- how does this relate to
order of initialization, for example.

Anthony

James Kanze

unread,
Sep 26, 2002, 1:48:50 PM9/26/02
to
alf_p_s...@yahoo.no.invalid (Alf P. Steinbach) wrote in message
news:<3d921004....@news.bluecom.no>...

> Thanks for that.

Hymen is right, and you need a lot more than just type information.
Consider the following case:

I define a base class in a header file, e.g.:

class Base
{
public:
virtual template< tyepname T >
void f( T const& ) = 0 ;
} ;

I also define a certain number of derived classes which override the
function.

In my main module, I instantiate an object of one of the derived
classes, say Derived. Let's further say that the class definition of
Derived is not even in a header file; it precedes my main function in
the source file.

That's my code.

In the dynamic object, there is a type DynObj defined. Like my Derived,
it is defined in one of the source files. I never see it, nor even know
it exists. There is also a function, which takes a Base& as parameter,
and calls the template function f with an object of type DynObj.

My main calls this function. We need an instantiation of Derived::f(
DynObj const& ). Where does this instantiation come from?

It can't come from my main module, because my main module has no idea
that DynObj even exists.

It can't come from the dynamic object, because the dynamic object has no
idea that Derived exists.

And it would take a major revolution in the format of executables and
dynamically loaded objects for the runtime to be able to determine the
implemenation of Derived::f, the interface (at least) of DynObj, and the
context of instantiation in the dynamic object. (Providing this
information would also increase the size of these files in a somewhat
spectacular way.)

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

---

Alf P. Steinbach

unread,
Sep 26, 2002, 2:54:03 PM9/26/02
to

I don't think "right" applies here. We're exploring unknown territory,
finding out about it; it's a question of degrees, practicality, and
so on. Anyway, I think I'll adopt the practice, recommended by some sf
author, to *apologize* whenever I suspect I may be perceived as "right".

Until now I've apologized when I was "wrong" about something.

That's just counter-productive.

>and you need a lot more than just type information.

So far I don't think so, if you just mean "in order to ensure type
consistency" or "in order to provide needed instantiations"
or both. I discuss this below, for your concrete example.

But if you mean to make the scheme practical, yes, then agreed.

As I've stated, I think some restriction on genericity is then needed,
e.g. a la Eiffel's generic types, because otherwise the whole thing
seems to become a morass of invisible and largely unforeseeable
constraints on which types a template parameter can stand for, etc.,
enforced by the linker, which then, it seems, must become much like a
compiler in its own right. And I don't like the idea of adding even
more sublanguage to C++, which is surely complex enough...

With that in mind,

>Consider the following case:
>
>I define a base class in a header file, e.g.:
>
> class Base
> {
> public:
> virtual template< tyepname T >
> void f( T const& ) = 0 ;
> } ;
>
>I also define a certain number of derived classes which override the
>function.
>
>In my main module, I instantiate an object of one of the derived
>classes, say Derived. Let's further say that the class definition of
>Derived is not even in a header file; it precedes my main function in
>the source file.
>
>That's my code.
>
>In the dynamic object, there is a type DynObj defined. Like my Derived,
>it is defined in one of the source files. I never see it, nor even know

>it exists. There is also a function [g], which takes a Base& as parameter,


>and calls the template function f with an object of type DynObj.

When seeing this the compiler must emit type information to the effect
that virtual template function f<DynObj> must exist for any call to g.

>My main calls this function [g].

On seeing this the compiler must emit type information to the effect that
g has been called, with a polymorphic argument.


>We need an instantiation of Derived::f(>DynObj const&). Where does this
>instantiation come from?

If that future hypothetical C++ doesn't yet have modules, i.e. the
compiler cannot consult the type information from the compilation unit
with g(), then the instantiation must be generated by the linker, e.g. from
some generic form generated by the compiler. If that doesn't seem to make
sense, read on.

>It can't come from my main module, because my main module has no idea
>that DynObj even exists.
>
>It can't come from the dynamic object, because the dynamic object has no
>idea that Derived exists.

I agree with both these (but see above). What I'm not sure about is what
you mean, precisely, by "dynamic object". Presumably from a DLL, but
is that a DLL with no associated type information? For a DLL with type
information, let the static linking do the job. That is, theoretically.
Also, since I don't know much about DLLs on Unices, if current
implementations don't support static type-checking then that convention
would have to be changed; change it would have to anyway. Still
theoretically, of course.

In practice I wouldn't want a linker that used hours on the job, only
to report that hey, your use of f<SomeType>() conflicts with a hidden
derived class which overrides f totally generically as


virtual template< tyepname T >
void f( T const& x )
{
x.BringPeaceToHeavenAndEarth(); // U2 says so.
}


and your SomeType, unfortunately, doesn't provide that member function...

This is, IMHO, an important practical problem in this context, that with
this scheme derived classes seem to be able to force invisible and largely
(for the programmer) unknowable constraints on existing base classes.

>And it would take a major revolution in the format of executables and
>dynamically loaded objects for the runtime to be able to determine the
>implemenation of Derived::f, the interface (at least) of DynObj, and the
>context of instantiation in the dynamic object. (Providing this
>information would also increase the size of these files in a somewhat
>spectacular way.)

Absolutely agreed.

Cheers,

- Alf

Allan W

unread,
Sep 26, 2002, 4:37:31 PM9/26/02
to
hyr...@mail.com (Hyman Rosen) wrote in message news:<10329917...@master.nyc.kbcfp.com>...

> Alf P. Steinbach wrote:
> > I don't know the details about Unix dynamic linking, but in
> > Windows there are three options:
>
> This problem is completely independent of platform.
> It has nothing to do with type checking at link time.
>
> In most implementations of C++, virtual methods of
> class templates are always instantiated whenever the
> template is instantiated, unlike non-virtual methods
> which are only instantiated if called. 14.7.1/9 talks
> about this. The reason is that when the class is
> instantiated, the compiler doesn't know whether the
> virtual function will be called from some other point,
> and must therefore provide a pointer to the function
> in the virtual table just in case.
>
> Exactly the same situation applies to virtual member
> function templates, but here it is impossible to
> instantiate all the cases, since there are an infinite
> number. The only possibility of success is if the
> compiler can know which instances it will need, and it
> can't know that if new functions can appear at runtime.

The number of classes could be large, but not infinite.
New functions don't appear at runtime -- the latest would
be link-time.

The OP's request is not impossible. Here's one way that it could
work:

1. The compiler would create a unique ID number for every
data type, excluding arrays and pointers. The ID numbers
would NOT be guaranteed to be the same after the program
was re-compiled or re-linked. For user-defined types,
this information might be kept with the typeid()
data -- how to handle classes without virtual functions is
an exercise left to the reader.

2. Whenever the compiler came across the declaration of a
virtual template function, it would generate two things:
- A hidden function. The address of this hidden function
would go into the vtable.
- A hidden data structure, possibly of type std::map or
something equivalent. This data structure will eventually
map the ID number of every type to an instantiation of
the virtual template instantiation.
If the virtual template function has multiple template
arguments, this might have to be a compound map, where
map entries lead to whole new maps. This too is left as
an exercise.

3. Whenever the compiler instantiates a virtual template
function, it would generate two things:
- The instantiation.
- A hidden object of some internal class type, where the
constructor updates the hidden data structure to refer to
the new instantiation.

4. When called, the hidden function would:
- Look up the address of the "real" instantiation
- Call it

I believe that this description proves that the idea isn't impossible,
just infeasible. After all, we still couldn't tell which instantiations
were needed until runtime, so we'd have to instantiate all of them.
In a project with just two virtual template functions and 2,000 different
data types, that's 4,000 instantiations, not counting all of the hidden
stuff I've enumerated above.

Niklas Matthies

unread,
Sep 26, 2002, 4:37:48 PM9/26/02
to
On Thu, 26 Sep 2002 17:48:50 +0000 (UTC), James Kanze <ka...@gabi-soft.de> wrote:
[...]

How about requiring overrides of a virtual template function to
specialize the template? Then the derived class needs to know about
the template arguments, the problem described above goes away, while
the remaining functionality still being quite useful.

-- Niklas Matthies
--
Avril Lavigne in bear pajama NOW!

Hyman Rosen

unread,
Sep 26, 2002, 6:46:08 PM9/26/02
to
Niklas Matthies wrote:
> How about requiring overrides of a virtual template function to
> specialize the template?

How do you know which specializations are needed? You don't, except
by knowing all callers. With dynamic linking, those callers may not
even exist at the time the program begins running.

Alf P. Steinbach

unread,
Sep 27, 2002, 11:31:25 AM9/27/02
to
On Thu, 26 Sep 2002 22:46:08 +0000 (UTC), hyr...@mail.com (Hyman Rosen) wrote:

>Niklas Matthies wrote:
>> How about requiring overrides of a virtual template function to
>> specialize the template?
>
>How do you know which specializations are needed?

In the scheme described by Niklas, a derived class need not override
all specializations. It might override none, one, or more. But it
might not override an unbounded set of specializations.

Thus, the question isn't meaningful for overrides in this limited
scheme -- what's left of the question is just the general problem
of determining needed specializations of the base class definition,
which has already been discussed.

The problem isn't then the specializations, but that the scheme
then essentially reduces to a way of specifying an unbounded set
of *possible* virtual functions in the class with the templated
function definition -- which IMHO brings in a lot of machinery
and overhead for very little gain.


>You don't, except by knowing all callers. With dynamic linking, those
>callers may not even exist at the time the program begins running.

I begin to suspect that there must be something fundamentally
different and untype-safe about some implementation(s) of dynamic
linking. Could you describe an instance of dynamic linking, except
explicit non type checked runtime loading of a DLL, that doesn't
provide static type checking? For example, in Windows a COM object
is typically, at the lowest levels, obtained by non type checked
explicit runtime loading, so that is not what I'm searching for here;
I think you're referring to something not so directly in conflict
with what we mean by type-safe / type-checking?

Cheers,

- Alf

Niklas Matthies

unread,
Sep 27, 2002, 12:34:22 PM9/27/02
to
On Thu, 26 Sep 2002 22:46:08 +0000 (UTC), Hyman Rosen <hyr...@mail.com> wrote:
> Niklas Matthies wrote:
> > How about requiring overrides of a virtual template function to
> > specialize the template?
>
> How do you know which specializations are needed?

You don't. You generate and include code for all overrides that are
being made by derived classes, whether they will be called or not, just
as with regular virtual functions. The only implicit instantiations are
from the template in the base class, which will be instantiated by the
module that does a call through a pointer or reference to a class that
didn't override that instantiation.

As for dynamic linking, here's how things can be pulled off:

The virtual function template (VFT) in the base class causes one entry
in the vtable to be created, which will point to a second table which
will contain pointers to the instantiations of the VFT. Let's call this
the VFT's ftable for short.

Every module that contains an invocation of the VFT for some specific
template argument list will also contain the corresponding (implicit)
instantiation of the VFT as defined by the base class, unless all
corresponding invocations are through pointers or references to classes
that override that instantiation, and unless the VFT as a whole or the
corresponding specialization was declared pure virtual. This means that
for any invocation of the VFT, there will already be at least one
corresponding instantiation in that module for the non-pure case. In the
pure case, no object of that class will be able to be instantiated, so
everything is fine as far as the single module is concerned.

Whenever a module is loaded which contains specializations or invoca-
tions of the VFT with new template argument lists (i.e. template
argument lists for which the already loaded modules contain neither
invocations nor specializations), the corresponding existing ftables
in the already loaded modules are resized to be able to hold the new
entries, which are initialized with pointers to the respective
specializations for each class. Also, any new ftables the module being
loaded may contain for new derived classes are resized appropriately
and filled with function pointers according to the ordering established
by the already loaded modules.

Then, similar to how regular functions are handled upon dynamic linking,
all affected invocations in all modules are adjusted to use the
appropriate indices into the ftable according to the ordering that
has been established so far. This is either done by directly patching
the program code or by letting invocations look up their indices in a
module-private table and patching this table.

If memory usage is an issue and many new spezializations are loaded
and unloaded frequently, a reverse process can be performed upon
unloading so that ftable entries for which no invocations are present
any more can be removed.

It appears to me that this works, and also doesn't require dramatically
more magic than dynamic linking already does. Or am I missing some
showstopper?

-- Niklas Matthies
--
Save Farscape - get informed and involved: http://farscape.wdsection.com/
Together, we can get Farscape back on air. Crackers *do* matter.

Anthony Williams

unread,
Sep 27, 2002, 12:36:49 PM9/27/02
to
ka...@gabi-soft.de (James Kanze) writes:

Yes, you need all the context information about the point of definition, and
the point of instantiation.

As I have said in another post, this is essentially like "export", but with
additional implementation details regarding building the vtable, and the fact
that it has consequences for derived classes.

If you are statically linking, then the problem is solved by requiring all
templated virtual functions to be exported, along with a small amount of code
to handle building the vtable at link time, and instantiating the derived
classes.

If you are dynamically linking, then the problem is expanded because you do
not have all the required information until link-time, which is now also
run-time. Therefore, unless you ship the compiler and the source code for all
modules whenever you ship the program, then you cannot do this for the general
case. (Of course, the compiler could package the source code and relevant
parts of the compiler into the DLLs, but the principle still stands). Shipping
such a large quantity of additional information would be unworkable. Also, it
means you wouldn't know until runtime whether or not there was a compilation
error, and you may need additional libraries when the derived classes are
instantiated.....

In short, templated virtual functions are not going to work with dynamic
linking, unless restrictions are put on the permitted instantiations, which
reduce it to a finite set, so all possible instantiations can be built a
priori --- if they failed to compile it wouldn't _have_ to be a compilation
failure unless that particular instantiation was actually used, which may
therefore cause a runtime linking failure "required instantiation of
derived::func<T> not present due to compilation failure".

However, I don't think that this is sufficient to prevent templated virtual
functions making it into the Standard, as I believe they are genuinely useful
constructs. Maybe this could be used as a driving example for adding
restricted templates to the language, something that would be useful for
generic programming, too.

Anthony

Hyman Rosen

unread,
Sep 27, 2002, 1:22:18 PM9/27/02
to
Alf P. Steinbach wrote:
> I begin to suspect that there must be something fundamentally
> different and untype-safe about some implementation(s) of dynamic
> linking.

I don't know of any implementations of dynamic linking that
deal with types at all. Whatever type safety there is comes
from the use of mangled names. Do you have examples of type-
safe dynamic linkers? What platform?

James Kanze

unread,
Sep 28, 2002, 12:36:21 AM9/28/02
to
alf_p_s...@yahoo.no.invalid (Alf P. Steinbach) wrote in message
news:<3d934bc0....@news.bluecom.no>...

> >> Thanks for that.

> >Hymen is right,

It depends on what we are talking about. I think his statement is that
virtual template functions are impossible for dynamically linked objects
unless we do template instantiation at (dynamic) link time.

Note that they are impossible even without dynamic linking unless we do
template instantiation at link time. There is no separately compiled
module that has enough information.

> We're exploring unknown territory, finding out about it; it's a
> question of degrees, practicality, and so on. Anyway, I think I'll
> adopt the practice, recommended by some sf author, to *apologize*
> whenever I suspect I may be perceived as "right".

> Until now I've apologized when I was "wrong" about something.

> That's just counter-productive.

> >and you need a lot more than just type information.

> So far I don't think so, if you just mean "in order to ensure type
> consistency" or "in order to provide needed instantiations" or both.
> I discuss this below, for your concrete example.

> But if you mean to make the scheme practical, yes, then agreed.

> As I've stated, I think some restriction on genericity is then needed,
> e.g. a la Eiffel's generic types, because otherwise the whole thing
> seems to become a morass of invisible and largely unforeseeable
> constraints on which types a template parameter can stand for, etc.,
> enforced by the linker, which then, it seems, must become much like a
> compiler in its own right.

That is precisely what I am saying. Virtual template functions requires
link time instantiation. When dynamically linked modules are present,
link time means run-time, so we have runtime instantiation.

> And I don't like the idea of adding even more sublanguage to C++,
> which is surely complex enough...

> With that in mind,

> >Consider the following case:

> >I define a base class in a header file, e.g.:

> > class Base
> > {
> > public:
> > virtual template< tyepname T >
> > void f( T const& ) = 0 ;
> > } ;

> >I also define a certain number of derived classes which override the
> >function.

> >In my main module, I instantiate an object of one of the derived
> >classes, say Derived. Let's further say that the class definition of
> >Derived is not even in a header file; it precedes my main function in
> >the source file.

> >That's my code.

> >In the dynamic object, there is a type DynObj defined. Like my
> >Derived, it is defined in one of the source files. I never see it,
> >nor even know it exists. There is also a function [g], which takes a
> >Base& as parameter, and calls the template function f with an object
> >of type DynObj.

> When seeing this the compiler must emit type information to the effect
> that virtual template function f<DynObj> must exist for any call to g.

It emits this information into the object file for g, I suppose.

> >My main calls this function [g].

> On seeing this the compiler must emit type information to the effect
> that g has been called, with a polymorphic argument.

That is already the case (except that the polymorphism is handled
directly be the generated code).

> >We need an instantiation of Derived::f(>DynObj const&). Where does
> >this instantiation come from?

> If that future hypothetical C++ doesn't yet have modules, i.e. the
> compiler cannot consult the type information from the compilation unit
> with g(), then the instantiation must be generated by the linker,
> e.g. from some generic form generated by the compiler. If that
> doesn't seem to make sense, read on.

It makes perfect sense, since it is exactly what I am saying. When
compiling main, the compiler doesn't know for which types the virtual
function will be called, so it doesn't know what functions to
instantiate. When compiling the dynamic object, the compiler doesn't
know what derived types exist, so it can't instantiate their functions.

An instantiation is only possible when both pieces of information are
available. In the case of dynamic linking, this is in fact at run-time.

> >It can't come from my main module, because my main module has no idea
> >that DynObj even exists.

> >It can't come from the dynamic object, because the dynamic object has
> >no idea that Derived exists.

> I agree with both these (but see above). What I'm not sure about is
> what you mean, precisely, by "dynamic object".

An object file that is dynamically linked.

> Presumably from a DLL, but is that a DLL with no associated type
> information? For a DLL with type information, let the static linking
> do the job. That is, theoretically. Also, since I don't know much
> about DLLs on Unices, if current implementations don't support static
> type-checking then that convention would have to be changed; change it
> would have to anyway. Still theoretically, of course.

You normally link against the dynamic object (called a shared object
under Unix) under Unix as well.

But the whole point of using dynamic linking is that the version you
actually pull in at run-time may be different from the one you linked
against. It must implement the same interface, but the implementation
details can differ. One of those implementation details that changes
might be the type used to call the virtual template, or the fact that it
calls the virtual template, whereas it didn't before.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

---

Alf P. Steinbach

unread,
Sep 29, 2002, 2:25:46 PM9/29/02
to
On Fri, 27 Sep 2002 17:22:18 +0000 (UTC), hyr...@mail.com (Hyman Rosen) wrote:

>Alf P. Steinbach wrote:
>> I begin to suspect that there must be something fundamentally
>> different and untype-safe about some implementation(s) of dynamic
>> linking.
>
>I don't know of any implementations of dynamic linking that
>deal with types at all. Whatever type safety there is comes
>from the use of mangled names.

That's how it is with object code files (the result of pure compilation)
and that's how it is with dynamic link libraries.

C++ global type safety *is* usually achieved by name mangling.

I don't think anything more can be expected with current technology.

Do you know of any other way that's compatible with the current standard?

(Note: in discussing future extensions we need not limit ourselves thus.)

>Do you have examples of type-safe dynamic linkers? What platform?

Using Visual C++ on the Windows platform two forms of dynamic linking,
namely where the DLL is loaded at program load time, and where deferred
automatic loading is used, can be type safe in the C++ sense.

The process is as follows.

When you implement a DLL in Visual C++, the compiler and linker produce
(1) a "bare" DLL, which is the system notion of DLL, and (2) an "import
library", which looks like a static library to the linker.

In other words, the .dll is the system part, and the .lib the C++ part.

Both can use name mangling to implement type safety, and that's the
default when creating a DLL from C++. The "import library" preserves
the C/C++ notion of static linking. It's also an optimization,
in particular, while functions in the import library are necessarily
resolved by mangled name, the import library itself *can* refer to
corresponding function numbers in the DLL, independent of names, or
it *can* refer to non-mangled names in the DLL.

When you link to the DLL you link against the "import library", which
is type safe, in the C++ sense of type safety.

When you run the program the program loader attempts to load all
referred DLLs (except for deferred loading, let's ignore that).
Having loaded the DLL into memory the further process can be different
depending on how the DLL was linked, e.g., function numbers or names.
Assuming names, which is the default for a C++ DLL, the loader then
proceeds to resolve the mangled names into function addresses.

If some scoundrel has replaced the DLL with a DLL of the same name,
number of functions/classes etc., even with the same C++ names, but
where the types don't match, the loader won't find the mangled
names. The result is then a system error message to the effect that
"the entry point GARBLEGARBLE could not be found in SOMEDLL.DLL",
and you won't even get a call of "main" (and no, it's not some
misconception of mine sneaking in here, it's the actual MS message).

The situation is not as clean with deferred loading...

Of course, there are ways around this typechecking, as there is in
general in C++. You only get typechecking by default.

Cheers,

- Alf

Hyman Rosen

unread,
Sep 30, 2002, 12:47:59 PM9/30/02
to
Niklas Matthies wrote:
> It appears to me that this works, and also doesn't require dramatically
> more magic than dynamic linking already does. Or am I missing some
> showstopper?

Let's look at the following detailed example. Base.h defines a struct
with a virtual member function template. Derived.h defines a struct
which inherits from this and overrides the member. Lib1.cpp and Lib2.cpp
each build into a dynamic library, and each contains a function which
invokes a particular specialization of the member template. Test.cpp
loops, reading the name of a dynamic library, loading it, getting a
pointer to the function it contains, and calling it with a pointer to
an object of the derived class.

None of the dynamic libraries have any knowledege of Derived.h. In fact,
it's possible that they were created years before Derived.h was ever
written. After all, that's the very foundation of virtual functions and
object-oriented programming. On the other hand, it's possible to create
new dynamic libraries while Test.cpp is in the middle of running.

Test.cpp has no knowledge of which dynamic libraries it will load,
since that is input supplied by the user.

Now, how do we implement this so that the invoked functions always
print "Derived:typename"?

Base.h:
#include <string>
#include <typeinfo>
struct Base
{
template <typename T> virtual std::string f()
{ return std::string("Base:") + typeid(T).name(); }
};

Derived.h:
#include "Base.h"
struct Derived : Base
{

template <typename T> virtual std::string f()
{ return std::string("Derived:") + typeid(T).name(); }
};

Lib1.cpp:
#include "Base.h"
#include <iostream>
extern "C" void FLib1(Base *p) { std::cout << p->f<int>() << "\n"; }

Lib2.cpp:
#include "Base.h"
#include <iostream>
extern "C" void FLib2(Base *p) { std::cout << p->f<double>() << "\n"; }

// etc., for as many LibN.cpp as you like

Test.cpp:
#include <iostream>
#include <loader.h>
#include "Derived.h"
int main()
{
std::string lib;
while (std::cin >> lib)
{
Derived d;
typedef extern "C" void (*PF)(Base *); // or whatever the syntax is
PF pf = reinterpret_cast<PF>(Loader::load(lib).get_func("F" + lib));
pf(&d);

Alf P. Steinbach

unread,
Sep 30, 2002, 12:49:03 PM9/30/02
to
On Sat, 28 Sep 2002 04:36:21 +0000 (UTC), ka...@gabi-soft.de (James Kanze) wrote:
>> As I've stated, I think some restriction on genericity is then needed,
>> e.g. a la Eiffel's generic types, because otherwise the whole thing
>> seems to become a morass of invisible and largely unforeseeable
>> constraints on which types a template parameter can stand for, etc.,
>> enforced by the linker, which then, it seems, must become much like a
>> compiler in its own right.
>
>That is precisely what I am saying. Virtual template functions requires
>link time instantiation. When dynamically linked modules are present,
>link time means run-time, so we have runtime instantiation.
>
>....

>
>An instantiation is only possible when both pieces of information are
>available. In the case of dynamic linking, this is in fact at run-time.

>...


>> Also, since I don't know much
>> about DLLs on Unices, if current implementations don't support static
>> type-checking then that convention would have to be changed; change it
>> would have to anyway. Still theoretically, of course.
>
>You normally link against the dynamic object (called a shared object
>under Unix) under Unix as well.
>
>But the whole point of using dynamic linking is that the version you
>actually pull in at run-time may be different from the one you linked
>against. It must implement the same interface, but the implementation
>details can differ. One of those implementation details that changes
>might be the type used to call the virtual template, or the fact that it
>calls the virtual template, whereas it didn't before.

Ok, I think I see where we sort of split up. When I think about the
*theoretical* possibility of the scheme I envision everything to be
supportive of the scheme. For dynamic linking that means some strict
canonical form of the type information for a DLL, and some checksum
of the type information that the loader can inspect (much like current
version numbers). In other words, the type information including
what's called with what would have to be part of the DLL interface, at
least at the C++ level.

With that there would be extremely little chance that a DLL specified
at static linking could be replaced by mistake by some incompatible
version where the DLL loading would not fail. I think that chance
would be comparable to someone altering the program executable. If
it weren't for the actual possibility of doing that I'd write "no way".

And so there could be no significant chance of new and unexpected usage
of a virtual template function, detectable only at run-time.

Anyway, thanks for a long and clear answer.

Disclaimer: since this posting may be quoted out of context by some
"I want a word in too!" person I have to repeat that I'm not supporting
the scheme, because it would IMHO be too inefficient and it seems to
allow derived classes to impose "invisible" restrictions on base
classes, and a fix for these problems would involve new sublanguage.

Cheers,

- Alf

Alf P. Steinbach

unread,
Sep 30, 2002, 1:46:04 PM9/30/02
to
On Wed, 25 Sep 2002 22:27:32 +0000 (UTC), hyr...@mail.com (Hyman Rosen) wrote:

>Alf P. Steinbach wrote:
>> I don't know the details about Unix dynamic linking, but in
>> Windows there are three options:
>
>This problem is completely independent of platform.

Well, it was in response to your statement that


>>That is, suppose that the function
>> void g(Base *p) { p->f<double>(); }
>>was loaded from a dynamic library. All of a sudden, we realize
>>that we need f<double> instantiated for all derived classes of
>>Base which override f<>. What do we do?

That cannot happen with statically type-checked DLLs.

For the virtual template scheme, the type checking would simply
have to be a bit (joke) more elaborate.

Not that I support the scheme; I've explained why earlier.

>It has nothing to do with type checking at link time.

On the contrary, that's where the type checking has
to go. With just a little bit of support at runtime,
e.g. checksum. Not that I support the scheme.


>In most implementations of C++, virtual methods of
>class templates are always instantiated whenever the
>template is instantiated, unlike non-virtual methods
>which are only instantiated if called. 14.7.1/9 talks
>about this. The reason is that when the class is
>instantiated, the compiler doesn't know whether the
>virtual function will be called from some other point,
>and must therefore provide a pointer to the function
>in the virtual table just in case.
>
>Exactly the same situation applies to virtual member
>function templates, but here it is impossible to
>instantiate all the cases, since there are an infinite
>number. The only possibility of success is if the
>compiler can know which instances it will need, and it
>can't know that if new functions can appear at runtime.

The only possibility of success is if the compiler *or
linker* can know which instances will be needed, which
they can, having full information about everything.

New functions cannot appear at runtime.

Again, not that I support the scheme.

Cheers,

- Alf

Niklas Matthies

unread,
Sep 30, 2002, 7:00:38 PM9/30/02
to
On Mon, 30 Sep 2002 16:47:59 +0000 (UTC), Hyman Rosen <hyr...@mail.com> wrote:
> Niklas Matthies wrote:
> > It appears to me that this works, and also doesn't require dramatically
> > more magic than dynamic linking already does. Or am I missing some
> > showstopper?
>
> Let's look at the following detailed example.
[...]

> struct Derived : Base
> {
> template <typename T> virtual std::string f()
> { return std::string("Derived:") + typeid(T).name(); }
> };

I believe you missed the crucial point about the suggestion I was
making. The above is illegal with my proposal since Derived does not
specialize the template, but instead provides a generic alternative.
A legal example according to my suggestion would be:

struct Derived : Base
{
template <> std::string f<int>() // overrides Base::f<int>()
{
return std::string("Derived: ") + typeid(int).name();
}
};

(In other words, my suggestion allows the creation of an infinite family
of virtual functions parameterized by template argument lists, and
derived classes can override a finite set of individual members of this
family, but they can't override the family as a whole.)

Any translation unit that instantiates objects of class Derived or
objects of subclasses of Derived that do not override Derived::f<int>()
will include a copy of Derived::f<int>(). When such a module is
dynamically loaded, the ftables for Base and its subclasses will be
adjusted to include an entry for f<int>() if not already present.
Similarly, any module thats calls f<int>() through a pointer-to-X where
X equals Base, or equals a subclass of Base that does not override
Base::f<int>(), will contain an instantiation of Base::f<int>().

-- Niklas Matthies
--
Save Farscape - get informed and involved: http://farscape.wdsection.com/
Together, we can get Farscape back on air. Crackers *do* matter.

---

Thomas Mang

unread,
Oct 5, 2002, 7:36:26 PM10/5/02
to

Hyman Rosen schrieb:

What I don't understand here is the difference between a single exported
template function, and a set of template functions provided through the whole
class hierarchy.

I am not very familiar with the separation compilation model, so what I say
below might be completely wrong. Please correct me if that's the case.

I belive the instantiation of the various template functions must be delayed
until link time, because the compiler itself has no knowledge in which object
file the definition of the template function is. It's the linker's job to do
that. So I think the object file which does refer an (yet not instantiated)
template function has to tell the linker it needs this function.
Why can't the dynamically linked in library do the same? The static compiled
file now provides an image of the class hierarchy it contains, and has all
virtual function templates declared to be exported. The dynamic linker
instantiates all these functions, puts them into a "virtual v-table", and the
dynamically linked in library in turn dereferences this one.


What's wrong with this scheme ?


best regards,

Thomas

Hyman Rosen

unread,
Oct 7, 2002, 11:45:27 AM10/7/02
to
Thomas Mang wrote:
> What's wrong with this scheme ?

Nothing in principle, but this means that a large
chunk of the compilation system has to be shipped
along with every program. Perhaps parsing can be
avoided, but the rest - instantiating the template,
optimizing, generating assembler or object code,
and so forth, would have to be done at runtime.

Sort of like JIT compilation for C++.

It's not a bad thing to think about. Such a system
would fit hand-in-glove with reflection capabilities,
to allow runtime class loading by name, and runtime
class generation. It's a big job, though. With any
luck, someone will pay EDG or ACT to produce it, or
maybe even Microsoft will do it as part of .NET.
Otherwise, I don't really see it happening.

Thomas Mang

unread,
Oct 8, 2002, 8:34:53 AM10/8/02
to
>
> Nothing in principle, but this means that a large
> chunk of the compilation system has to be shipped
> along with every program. Perhaps parsing can be
> avoided, but the rest - instantiating the template,
> optimizing, generating assembler or object code,
> and so forth, would have to be done at runtime.

>
>


> It's not a bad thing to think about. Such a system
> would fit hand-in-glove with reflection capabilities,
> to allow runtime class loading by name, and runtime
> class generation. It's a big job, though.

Yes, it certainly would be.

However, I think the benefit of having virtual template functions would be
big, too. (At least I have some code which could me made MUCH easier by
virtual template functions).

Certainly, dynamic linking makes everything much more complicated. But why
prevent virtual template functions from static linking (Yes I know, then
there is inconsistency on the language features based solely on the linking
method) ?. At least this one shouldn't be that difficult to implement (I
think the whole exporting of templates was more difficult to implement).

Anyway, from a programmers point of view, I don't think stuff such as virtual
template functions aren't good candidates for getting dynamically linked.
At least I would be abolutely happy and satisfied if this feature would be
restricted to static linking.


best regards,

Thomas

0 new messages