template <int x, int y> struct S {}; // [1]
template <int w, int z> struct S {}; // [2] <-- ill-formed
standard, common C++ 的东西禁止这样做。
Names denote entities (or labels, but let's ignore that)。姓名come from declarations。定义是subset of a declaration,所以它也引入了名称。
one-definition rule 说:
任何翻译单元不得包含任何变量、函数、类类型、枚举类型或模板的多个定义。
在语句[1] 中,创建了一个模板实体。该实体由名称 S 表示。
在语句[2] 中,创建了一个模板实体。该实体由名称 S 表示。
这两个名字are the same。如果一个名称表示一个实体(如前所述),那么在适当范围内的相同名称表示同一个实体。因此,两个语句都声明了同一个实体。
ODR 禁止的。
template <> struct S<6+1,4+3> {}; // [5]
template <> struct S<2+5,8-1> {}; // [6] <-- ill-formed
从语法上讲,S<6+1,4+3> 是 simple-template-id。现在,有人可能会认为这使它成为a class template partial specialization definition。但它没有,因为模板参数为空,即makes this an explicit specialization。即便如此,S<6+1,4+3> 仍然是这个定义的名称。并且明确的专业化定义仍然是定义。
那么问题来了,S<6+1,4+3> 和 S<2+5,8-1> 同名吗?
以下是关于我们如何判断same name is 的规则的摘录:
它们是 template-ids,它们引用相同的类、函数或变量 ([temp.type])
simple-template-id 在语法上是 template-id 的子集。那么这两个 simple-template-id 是否“引用同一个类、函数或变量”?
这由complex set of rules 决定。特别要注意:
它们对应的整数或枚举类型的非类型模板参数具有相同的值
6+1 和 2+5 是相同的值。 4+3 和 8-1 是相同的值。因此,这两个 simple-template-id 是相同的名称,因此是相同的实体。并且由于这两个定义定义了同一个实体,这违反了 ODR,如前所述。
部分模板特化是另一回事。
template <int x> struct S<x,5+2> {}; // [3]
template <int w> struct S<w,3+4> {}; // [4] <-- ill-formed
前面围绕simple-template-id 的逻辑工作......到了一定程度。部分特化使用 simple-template-id 作为它们的名称,因此它们引入的实体使用相同的规则来测试等价性。
但是,这些规则实际上并没有说明这里会发生什么。 x 和 w 不是值;它们是模板参数。他们的实际价值只有在选择他们的专业时才能知道。而另一个equivalence rules 并没有真正谈论当模板参数是模板参数时会发生什么。
所以技术上,看起来这些定义并不相同。不过……
根据how a template specialization is chosen 的规则,语句[3] 和[4] 引入了entirely ambiguous 的部分特化。看,在特化之间进行选择的规则涉及一组复杂的事物,包括将conversion of your partial specializations 放入一系列函数声明中,并使用template function overloading rules 对其进行排序。所以我没有引用。
归结为您的两种类型的方法是,您尝试实例化的任何 S<value> 都将是模棱两可的。无法从[4] 中检测到[3],因此任何使用其中任何一个的尝试都是错误的。
所以你的编译器基本上是抢先一步,意识到你不可能使用任何一种专业化,并告诉你你的代码被破坏了。
我可能在规范中的某个地方遗漏了一些东西,实际上说名称是相同的,因为它们显然是相同的名称。但是我没找到。