C++ gcc与带有可变参数加上相同类型额外参数的部分特殊化上的clang行为

C++ gcc与带有可变参数加上相同类型额外参数的部分特殊化上的clang行为,c++,c++11,variadic-templates,template-specialization,C++,C++11,Variadic Templates,Template Specialization,以下代码: #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

以下代码:

#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;
}
#包括
模板
结构A{
};
模板
结构A{
};
int main(){
a0;
A a2;
返回0;
}
…未使用
g++
(版本
5.1.0
5.3.0
)编译,原因是:

错误:部分专用化并不比主模板更专用,因为它用包扩展替换多个参数

…但编译时会发出
clang

是否允许声明此类局部专业化


旁注:实际上,专门化是危险的,因为
A
无法同时使用两个编译器进行编译(模板参数的数目错误)。

gcc是正确的,代码格式错误,因为专门化实际上并没有更专门化


[temp.class.spec]中的规则是(作为链接h/t t.C.的结果):

在类模板部分专门化的参数列表中,以下限制适用:[……]专门化应比主模板(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
模板
无效_uf(A);//主要的,重要的
模板
无效_uf(A);//专业化
然后检查偏序规则。这又涉及到为每个模板参数合成新的类型/值,并查看推导是否可以在任一方向上成功

明确地说,专业化的推导在主代码中失败(由于
N
vs
0
)。在另一个方向,从[临时扣除部分]:

如果
A
是从函数参数包转换而来,并且
p
不是参数包,则类型推断失败

由于我们试图先根据一个包推断出
T
,所以这个方向的推断也失败了。这意味着两个合成函数模板都不比其他模板更专业化,这反过来意味着类模板专业化并不比主模板更专业化。因此,gcc拒绝是正确的。

考虑:

template <class T, T first, T... rest>
struct X{};

template<class T, T... rest>
struct X<T, rest...>{};

要允许
A
,必须更改第一个模板。现在进行专门化已经太晚了。@Jarod42是的,我知道这样的模板实例化是错误的,我只是想问一下只使用
T。。。args
g++
中引发错误,但不是
clang
(重新组织问题以使其更清楚)。GCC是正确的。这是一个格式错误的per(有些不足为奇,因为它是由GCC的维护人员报告的)。@T.C.哦,它不是一个函数参数包,没关系。
//specialization
template<typename T,
         T first,
         T... args>
struct A<0, T, first, args...> {
};