'Conflicting template definitions and ODR

Imagine a situation where I have two distinct translation units a.cpp

#include <iostream>

double bar();

template <typename T>
T foobar(T t) {
    return t;
}

int main() {
    std::cout << "foobar called from b.cpp: " << bar() << '\n';
    std::cout << "foobar called from a.cpp: " << foobar(1.) << '\n';
}

and b.cpp:

template <typename T>
T foobar(T t) {
    return t + 1.;
}

double bar() {
    return foobar(1.);
}

I know that for templates, there are exceptions to the ODR, i.e. the compiler will mark instantiated function templates as such and will strike out all but one during the linking process. I noticed that the compiler doesn't actually care whether the generated codes of such instantiations at different translation units are actually identical or at least equivalent.

In the code above, this is the case. When compiling, linking and running with

c++ a.cpp b.cpp -o result -std=c++17 && ./result

it will yield the result

foobar called from b.cpp: 1
foobar called from a.cpp: 1

So apparently, the instantiation inside the object file b.o got thrown away in favour for that one from a.o. When compiling and linking with b.cpp and a.cpp swapped, like

c++ b.cpp a.cpp -o result -std=c++17 && ./result

the result will be

foobar called from b.cpp: 2
foobar called from a.cpp: 2

so the exact opposite happens: the instantiation that got mentioned first in the list of to-be-linked object files will be the one that survives. Is such a behaviour defined somewhere within the standard? Depending on the build system, the order in which the object files are mentioned can be rather arbitrary, but, as in such examples it leads to very different programs and possibly cumbersome bugs. Even if I try to explicitely instantiate the version from a.cpp by adding

template double foobar<double>(double);

it will not make the foobar<> template from a.cpp survive when mentioning b.o before a.o in the linker list.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source