Consider the following C++11 application:
A.cpp:
template<typename T>
struct Shape {
T x;
T area() const { return x*x; }
};
int testA() {
return Shape<int>{2}.area();
}
B.cpp:
template<typename T, typename U = T>
struct Shape {
T x;
U y;
U area() const { return x*y; }
};
int testB() {
return Shape<int,short>{3,4}.area();
}
Main.cpp:
int testA();
int testB();
int main() {
return testA() + testB();
}
Although it compiles (as long as A and B are in separate TUs), it doesn't look right, and I'm having trouble figuring out why.
Hence my Question: Does this violate ODR, overloading, or any other rule, and if so, what sections of the Standard are violated and why?
A template function can be overloaded either by a non-template function or using an ordinary function template.
You may overload a function template either by a non-template function or by another function template. The function call f(1, 2) could match the argument types of both the template function and the non-template function.
Can there be more than one argument to templates? Yes, like normal parameters, we can pass more than one data type as arguments to templates.
It is an ODR violation. Template names have linkage. And both those template names have external linkage, as [basic.link]/4 says:
An unnamed namespace or a namespace declared directly or indirectly within an unnamed namespace has internal linkage. All other namespaces have external linkage. A name having namespace scope that has not been given internal linkage above has the same linkage as the enclosing namespace if it is the name of
- [...]
- a template.
And on account of that, since both templates share a name, it means that [basic.def.odr]/5 applies:
There can be more than one definition of a [...] class template (Clause [temp]) [...] in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then
- each definition of D shall consist of the same sequence of tokens; and
- [...]
If D is a template and is defined in more than one translation unit, then the preceding requirements shall apply both to names from the template's enclosing scope used in the template definition ([temp.nondep]), and also to dependent names at the point of instantiation ([temp.dep]). If the definitions of D satisfy all these requirements, then the program shall behave as if there were a single definition of D. If the definitions of D do not satisfy these requirements, then the behavior is undefined.
Not the same sequence of tokens by a margin.
You can easily resolve it, as Jarod42 suggested, by putting both definitions of the templates into an unnamed namespace, thus giving them internal linkage.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With