If I define a function (maybe a class member function but not inlined) in a header file that is included by two different translation units I get a link error since that function is multiply defined. Not so with templates since they are not compilable types until the compiler resolves a declaration of an object of a templatized type. This made me realize I don't know where compiled template code resides and how it is linked since C++ does not just create multiple copies of code to define SomeTemplateClass. Any info would be appreciated. Thanks!
-
1It depends on compiler (as it is not specified by the standard) and there are several techniques used. – Martin York Feb 23 '11 at 18:04
-
9That's pretty f'd up Alexandre since very few books will actually go over this and you didn't mention one where you expect the answer to be. OP is actually asking a good question about the one-definition rule. – Edward Strange Feb 23 '11 at 18:06
4 Answers
There are 3 implementation schemes used by C++ compilers:
greedy instantiation, where the compiler generates an instantiation in each compilation unit that uses it, then the linker throws away all but one of them (this is not just a code-size optimization, it's required so that function addresses,
static
variables, and the like are unique). This is the most common model.queried instantiation, where the compiler has a database of instantiations already done. When an instantiation is needed, the DB is checked and updated. The only compiler I know which uses this is Sun's, and it isn't used by default anymore.
iterated instantiation, where the instantiations are made by the linker (either directly or by assigning them to a compilation unit, which will then be recompiled). This is the model used by CFront -- i.e. historically it was the first one used -- and also by compilers using the EDG front-end (with some optimisations compared to CFront).
(See C++ Templates, The Complete Guide by David Vandevoorde and Nicolai Josuttis. Another online reference is http://www.bourguet.org/v2/cpplang/export.pdf, which is more concerned about the compilation model but still has descriptions of the instantiation mechanisms).

- 51,233
- 8
- 91
- 143
-
Ah, that seem to be the correct answer, including a reference to read more about it. Great answer, `+1` from me! – sbi Feb 23 '11 at 18:16
All template functions are implicitly inline. Just as methods defined in the class declaration are implicitly inline.
When I say implicitly inline I mean the more modern usage of the word. See my lengthy description here.
In short, inline
, static
, and extern
are all sibling linkage directives. inline tells the linker to ignore duplicate definitions of a function. Generally this means the linker will pick one definition and use it for all compilation units. I don't know of any compilers that do or did leave all duplicate template code in the final executable.
Where are template instantiations stored?
They are stored in the same way in the same place as inline functions. The details of that are compiler specific.
This is implementation specific.
Some compilers will generate the same template instances over and over for each translation unit they are instantiated in and let the linker fold the duplicates.
Templates got a bad reputation for "code bloat" when linkers weren't yet up to that task. Nowadays this is probably undeserved. Some implementations will even fold different instantiations when they compile to the same target machine code. (Like f<A*>()
and f<B*>()
, as pointer types are just addresses in the generated machine code.)
Others will defer template compilation until link-time instead, and there might be still other ways to deal with this. As I said, it's up to the implementation.
These all have different advantages and disadvantages. Absent of a true module concept I doubt anyone will come up with the perfect scheme.
With export
there used to be a requirement for compilers to pre-compile template code and instantiate at request. However, except for one vendor nobody implemented export
for their compiler, and now it's removed.

- 219,715
- 46
- 258
- 445
-
A side note about export. It wasn't deprecated, it was removed! The comeau group asked that the feature be removed rather than just deprecated. As they had the only compiler that implemented export the committee agreed. – deft_code Feb 23 '11 at 18:28
-
Yes, you're right, it was removed. And that was proposed by EDG (on which Comeau is based), who strongly resisted accepting that into the standard (but were overruled) and were the only ones who implemented it. You gotta respect these guys! – sbi Feb 23 '11 at 18:48
-
I know it is an old thread, but do you have any reference for the statement "Some implementations will even fold different instantiations when they compile to the same target machine code" that you made? – ajcaruana Feb 15 '18 at 17:23
-
@ajcaruana: ISTR VC folks boasting of they compiler folding different template instantiations. ICBWT when it comes to the exact details of what VC did back then. – sbi Mar 02 '18 at 14:02
It actually does create multiple copies. Those copies are special and don't violate the one-definition rule. Some linkers will come along, remove the copies, and relink the functions using them; not all do.

- 40,307
- 7
- 73
- 125
-
That's not true for all compilers. IIRC, Comeau defers instantiation until link time. I think cfront also did that. – sbi Feb 23 '11 at 18:10
-
1All must do, otherwise pointers to a function generated from the same function template won't compare equal as the standard requires. – Maxim Egorushkin Feb 23 '11 at 18:22
-
@Maxim you comment is correct if a little vague. _All must do_ => _All linkers must remove the duplicate copies_. – deft_code Feb 23 '11 at 18:30
-
@Maxim - That's not as clear as you might expect. Inline functions also have this requirement and as you might expect, a linker is not required to remove all copies. All that's actually required is that the address is the same **if and where taken**. – Edward Strange Feb 23 '11 at 18:50
-
@Crazy Eddie: the C++ standard only specifies the **minimum requirement** that, as you correctly pointed, the addresses to the same function must compare equal only **if and where taken**. Enter the reality. Because dynamic linking is currently outside of the scope of C++ (as multithreading is), real-world toolchains that support shared libraries must address this issue somehow, because it is not known if an address of a function is ever taken in a shared library that may also be loaded only at run-time. gcc toolchain addresses this by utilizing what is known as vague linkage. – Maxim Egorushkin Feb 23 '11 at 20:07
-
To be completely precise, it is the runtime linker which resolves addresses of the same function multiply defined in several binaries to the same address. – Maxim Egorushkin Feb 23 '11 at 20:18