Jodocus
Jodocus

Reputation: 7591

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.

Upvotes: 3

Views: 1168

Answers (1)

Jarod42
Jarod42

Reputation: 217428

I know that for templates, there are exceptions to the ODR

There are no exceptions for ODR for template, it is just that template functions are inline.

And your program has ODR violation.
You would have similar issue with regular inline functions.

Upvotes: 5

Related Questions