Why is it that the non template functions are treated differently to templates when it comes to multiple definitions?
There are historical and compatibility issues involved here. Some of the requirements come from C, that is the way it worked. There are also reasons related to what templates are, they are code generators; when required, the compiler needs to generate the code, consequently it needs to see the code when it generates it. This has a knock on effect that there will be multiple definitions, so rules are required to resolve those issues.
Simply put; templates behave (w.r.t. linking) as if they had a single definition in the program, hence they do not behave the same during compilation and linking as non-templates (that are not declared with inline
) - in particular w.r.t. functions. If the non-templates are declared inline
, similar behaviour is seen.
Standard references here include;
Some background, most of the issues here relate to linkage, what is linkage? §3.5/2 [basic.link]
A name is said to have linkage when it might denote the same object, reference, function, type, template, namespace or value as a name introduced by a declaration in another scope:
- When a name has external linkage, the entity it denotes can be referred to by names from scopes of other translation units or from other scopes of the same translation unit.
- When a name has internal linkage, the entity it denotes can be referred to by names from other scopes in the same translation unit.
- When a name has no linkage, the entity it denotes cannot be referred to by names from other scopes.
Some general rules relating to functions and variable, for the program as a whole and each of the translation units.
§3.2/1 [basic.def.odr]
No translation unit shall contain more than one definition of any
variable, function, class type, enumeration type, or template.
And
§3.2/4 [basic.def.odr]
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program...
§3.2/6 [basic.def.odr]
There can be more than one definition of a class type (Clause [class]), enumeration type ([dcl.enum]), inline function with external linkage ([dcl.fct.spec]), class template (Clause [temp]), non-static function template ([temp.fct]), static data member of a class template ([temp.static]), member function of a class template ([temp.mem.func]), or template specialization for which some template parameters are not specified ([temp.spec], [temp.class.spec]) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements....
If D
is a template and is defined in more than one translation unit, then the preceding requirements shall apply both to names from the template's enclosing scope used in the template definition ([temp.nondep]), and also to dependent names at the point of instantiation ([temp.dep]). If the definitions of D
satisfy all these requirements, then the behavior is as if there were a single definition of D
. If the definitions of D
do not satisfy these requirements, then the behavior is undefined.
Some informal observations on the above list including the classes, templates etc. These are typical elements often found in header files (of course not exclusively or limited to headers). They are given these special rules to make everything work as expected.
What about class member functions? §9.3 [class.mfct]
1/ A member function may be defined ([dcl.fct.def]) in its class definition, in which case it is an inline member function ([dcl.fct.spec]), or it may be defined outside of its class definition if it has already been declared but not defined in its class definition. A member function definition that appears outside of the class definition shall appear in a namespace scope enclosing the class definition...
2/ An inline member function (whether static or non-static) may also be defined outside of its class definition provided either its declaration in the class definition or its definition outside of the class definition declares the function as inline
or constexpr
. [ Note: Member functions of a class in namespace scope have the linkage of that class. Member functions of a local class ([class.local]) have no linkage. See [basic.link]. — end note ]
So basically, member functions not defined in the class definition and not implicitly inline
, hence the "normal" rules apply and hence can only appear once in the program.
And template, what does it say about linkage ? §14/4 [temp]
A template name has linkage ([basic.link]). Specializations (explicit or implicit) of a template that has internal linkage are distinct from all specializations in other translation units... Template definitions shall obey the one-definition rule ([basic.def.odr]).