The ODR is relaxed for templates
The ODR is "relaxed" for templates and for inline functions/variables.
It is possible for a template to appear in multiple translation units, such as:
// a.cpp
template <int N> int foo() { return N; }
// b.cpp
template <int N> int foo() { return N; }
Normally, this is not the result of copy/paste, but a consequence of including headers. The relevant wording is in [basic.def.odr] p14:
For any definable item D
with definitions in multiple translation units,
- if
D
is a non-inline non-templated function or variable, or
- if the definitions in different translation units do not satisfy the following requirements,
the program is ill-formed; [...]
ODR violations are still possible
Note that the definition can appear in multiple translation units without violating the ODR, but this definition needs to be identical everywhere.
// a.cpp
template <int N> int foo() { return N; }
// b.cpp
template <int N> int foo() { return 0; } // IFNDR
The program is ill-formed, no diagnostic required because the definitions are not the same.
This is also why it's important to use headers; it makes sure that the same symbols are copied/pasted into every translation unit.
What about code duplication?
This issue is resolved by the linker. A program would be ill-formed if any of the definitions weren't the same.
It is certain that foo<0>
in a.cpp
and foo<0>
in b.cpp
must be exactly the same.
As a result, the linker can arbitrarily pick one of the two, and remove the other from the executable.
This feature is also called weak symbols.