Seems I lack some rudimentary knowledge how templates work. Consider a program consisting of a common header file that introduces a variable template being a wrapper on std::array and two sources that include the header.
header.h
#ifndef HEADER_H
#define HEADER_H
#include <array>
template <typename T, auto N> std::array<T, N> arr;
void printArr();
#endif
source1.cpp
#include <iostream>
#include "header.h"
void printArr()
{
std::cout << &arr<int, 5> << std::endl;
}
source2.cpp
#include <iostream>
#include "header.h"
int main() {
std::cout << &arr<int, 5> << std::endl;
printArr();
return 0;
}
The program produces following prints:
0x565146e1c160
0x565146e1c160
Both prints produce the same memory address so the same instance is being manipulated.
My question is why the linker does not raise an error due to multiple definitions at link-time? Is this because the variable template is just a template and respective instances of the template are marked as weak which in turn produces a unique object?
>Solution :
The one-definition rule is relaxed for inline functions and variables, as well as for function templates and variable templates:
For any definable item
Dwith definitions in multiple translation units,
- if
Dis 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; […]
In short, the restrictions mean that arr can be defined in multiple translation units because it is a variable template. However, it must be defined exactly the same way in every TU.
// source1.cpp
template <typename T, auto N>
std::array<T, N> arr;
// source2.cpp
template <typename T, auto N>
std::array<T, N> arr; // OK
// source3.cpp
template <typename T, auto>
std::array<T, 10> arr; // ill-formed, no diagnostic required
The reason why this doesn’t produce a linker error is that that the emitted symbols (e.g. arr<int, 5> with its name mangled) are weak. Similar to inline variables, the linker chooses one of N available definitions under the assumption that all of them are identical. If you follow the rules in [basic.def.odr], then this assumption is fair.
See Also
- Are variable templates declared in a header, an ODR violation? (the answers here explain how this was worded in the C++ standard historically)