c++ - gcc vs clang 在具有可变参数和相同类型的额外参数的部分特化上的行为

标签 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> a0;
    A<2, int, 1, 2> a2;
    return 0;
}

...不编译 g++ (版本 5.1.05.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 and P is not a parameter pack, type deduction fails.

因为我们试图针对一个包推导T first,推导在这个方向上也是失败的。这意味着合成函数模板都不比其他模板更特化,这反过来意味着类模板特化并不比主模板更特化。因此,gcc 拒绝是正确的。

关于c++ - gcc vs clang 在具有可变参数和相同类型的额外参数的部分特化上的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36293088/

相关文章:

c++ - 在 for 循环中声明 vector 运算

c# - 如何从图像中访问检测到的人脸中的人脸像素?

c++ - std::atomic 应该是易变的吗?

c++ - 如何区分存储在模板类中的类型

c++ - 如何在类成员函数内部的printf中获取编译警告

c++ - 模板元编程c++中的匹配变量

c++ - 如何将variant <Ts…>的值移动到variant <T,Ts…>中?

c++ - 具有 C 链接和 C++ 实现的不透明结构

c++ - 一个内部表示不暴露给用户并且可以透明改变的类,这个例子是什么?

c++ - ISO C++标准草案