Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why C++ variable template does not raise multiple definitions error?

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

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

#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 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; […]

[basic.def.odr] p14

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

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading