以下代码:
#include <cstddef>
template <size_t N,
typename T,
T first,
T... rest>
struct A {
};
template<typename T,
T... args>
struct A<0, T, args...> {
};
int main () {
A<0, int, 1> a0;
A<2, int, 1, 2> a2;
return 0;
}
...不编译 g++
(版本 5.1.0
和 5.3.0
)由于:
error: partial specialization is not more specialized than the primary template because it replaces multiple parameters with a pack expansion
...但使用 clang
编译.
是否允许声明这样的部分特化?
旁注:实际上,自 A<0, int>
以来,特化是危险的两个编译器都无法编译(模板参数数量错误)。
最佳答案
gcc 是正确的,代码格式错误,因为特化实际上并没有更特化。
来自 [temp.class.spec] 的规则是(作为 DR 1495 的结果,链接的 h/t T.C.):
Within the argument list of a class template partial specialization, the following restrictions apply: [...] The specialization shall be more specialized than the primary template (14.5.5.2).
为了确定这一点,我们将两者重写为合成函数模板:
template <size_t N, class T, T first, T... rest>
void __f(A<N, T, first, rest...> ); // primary
template <class T, T... args>
void __f(A<0, T, args...> ); // specialization
然后通过部分排序规则。反过来,这涉及为每个模板参数合成新类型/值,并查看推导是否可以在任一方向上成功。
毫无疑问,特化的推导失败了(由于 N
vs 0
)。在另一个方向,来自 [temp.deduct.partial]:
If
A
was transformed from a function parameter pack andP
is not a parameter pack, type deduction fails.
因为我们试图针对一个包推导T first
,推导在这个方向上也是失败的。这意味着合成函数模板都不比其他模板更特化,这反过来意味着类模板特化并不比主模板更特化。因此,gcc 拒绝是正确的。
关于c++ - gcc vs clang 在具有可变参数和相同类型的额外参数的部分特化上的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36293088/