template <int x, int y> struct S {}; // [1]
template <int w, int z> struct S {}; // [2] <-- ill-formed
This is forbidden by standard, common C++ stuff.
Names denote entities (or labels, but let's ignore that). Names come from declarations. A definition is a subset of a declaration, so it too introduces names.
The one-definition rule says:
No translation unit shall contain more than one definition of any variable, function, class type, enumeration type, or template.
In statement [1]
, a template entity is created. That entity is denoted by the name S
.
In statement [2]
, a template entity is created. That entity is denoted by the name S
.
These two names are the same. If a name denotes an entity (as previously established), then the same name within the appropriate scope denotes the same entity. Thus, both statements declare the same entity.
Which is forbidden by the ODR.
template <> struct S<6+1,4+3> {}; // [5]
template <> struct S<2+5,8-1> {}; // [6] <-- ill-formed
Grammatically speaking, S<6+1,4+3>
is a simple-template-id. Now, one might think that this makes this into a class template partial specialization definition. But it doesn't, because the template parameter is empty, which makes this an explicit specialization. Even so, S<6+1,4+3>
is still the name of this definition. And explicit specialization definitions are still definitions.
So the question is, is S<6+1,4+3>
the same name as S<2+5,8-1>
?
Here's an excerpt from the rules about how we tell what the same name is:
they are template-ids that refer to the same class, function, or variable ([temp.type])
A simple-template-id is grammatically a subset of template-id. So do those two simple-template-ids "refer to the same class, function, or variable"?
That is determined by a complex set of rules. In particular, note:
their corresponding non-type template arguments of integral or enumeration type have identical values
6+1
and 2+5
are the same value. 4+3
and 8-1
are the same value. Therefore, those two simple-template-ids are the same name and therefore the same entity. And since these two definitions are defining the same entity, that violates ODR, as previously indicated.
Partial template specialization is another matter.
template <int x> struct S<x,5+2> {}; // [3]
template <int w> struct S<w,3+4> {}; // [4] <-- ill-formed
The preceding logic surrounding simple-template-id
works... to a point. Partial specializations use simple-template-ids for their names, so the entities they introduce use the same rules to test equivalence.
However, those rules don't actually say what happens here. x
and w
aren't values; they are template parameters. Their actual value can only be known when their specializations are chosen. And the other equivalence rules don't actually talk about what happens when a template argument is a template parameter.
So technically, it would seem that these are not the same definition. However...
In accord with the rules of how a template specialization is chosen, the statements [3]
and [4]
introduces partial specializations that are entirely ambiguous. See, the rules for selecting between specializations involves a complex set of things, including a conversion of your partial specializations into a series of function declarations and using template function overloading rules to sort it out. So I'm not quoting that.
The way it boils down for your two types is that any S<value>
that you try to instantiate will be ambiguous. There's no way to detect [3]
from [4]
, so any attempt to use either will be ill-formed.
So your compiler basically jumps the gun, realizing that you cannot possibly use either specialization, and tells you that your code is broken.
There may be something I've missed somewhere in the spec that actually says that the names are the same, since they obviously are the same name. But I haven't found it.