Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class template overloading across TUs

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?

like image 710
rustyx Avatar asked Jan 23 '18 10:01

rustyx


People also ask

Can class templates be overloaded?

A template function can be overloaded either by a non-template function or using an ordinary function template.

How do you overload a class template in C++?

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 arguments to templates?

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.


1 Answers

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.

like image 146
StoryTeller - Unslander Monica Avatar answered Sep 18 '22 20:09

StoryTeller - Unslander Monica