Re: Friday afternoon C trivia:



Pertti Kellomaki wrote:
Stefan Reuther wrote:
We were talking about resource-constrained systems, weren't we?
Templates are not Generics, thus templatizing code blows up your binary
size, and complicates linking a lot.

Hopefully the development system is not resource constrained,
just the target. I know that a half-baked implementation can
do stupid things like produce two instances of a template even
though the resulting code is identical, but this is a quality
of implementation issue, not something intrinsic to templates.

So far, all schemes of template management I've encountered had their
drawbacks in practice.

The "Borland method" - placing all template instances in all object
files, and sorting out duplicates at link time - so far has been the
friendliest one, although it blows up object file sizes and link times,
and in practice linkers don't manage to eliminate all dupes. Some
methods appear a few hundred times in our final binary.

The "repository" method - putting template instances into separate
object files at magic places -, and the "association" method - picking
an object file using the template at random and placing the template
instance there - have bad interaction with static libraries. We're using
the same set of object files to build multiple binaries. When building
a.exe, the compiler decides std::string goes into obj1.o, when building
b.exe, it decides std::string goes into obj2.o - boom.

All these methods have the disadvantage that you'll never know where
your code will end up. We're in comp.arch.embedded? Unlike on desktop
environments, where all memory is equal, I occasionally need to assign
specific code into specific sections, using a linker file. When I want
to put a particular template instance into L1 memory, I don't know which
object file to use. And when I want a specific object file, I don't know
whether an unexpected template instance will fill up my precious L1.

Templating is a purely compile time phenomenon, so there is no
reason why it should affect binary size at all.

Templates are instantiated to generate code. Unless you're using
templates that are completely inlined and optimized away (which is
indeed useful, and which I use all the time), of course it affects the
binary size.

In fact, I would argue that compilers should be able to exploit
templating to reduce binary size. It is not unheard of to have
functions with identical algorithmic behavior but different
signatures. There may be compilers out there that aggressively
merge such functions if they result in the same machine code,
but clearly it would be more efficient to examine known instances
of a template rather than to examine all pairs of functions.

Do these compilers/linkers actually exist? I doubt it, and just hoping
that they might exist someday doesn't help me today.

Such a feature would be pretty hard to do standards-conformant anyway.
In particular, the compiler may *not* merge functions of identical
signature, because programmers can expect this to work
void (*foo)() = func1;
assert(foo != func2);
even if func1 and func2 have the same body / machine code. I'm not
entirely sure whether it would be permitted to merge functions with
different signatures, at least those cannot be compared without a cast.


Stefan

.


Quantcast