g++ 和 clang++ 自动参数模板特化的不同行为

g++ and clang++ different behaviour with template specialization for auto argument

使用 C++17 auto 模板参数我遇到了另一个 g++/clang++ 分歧。

给定以下简单代码

template <auto>
struct foo;

template <int I>
struct foo<I>
 { };

int main ()
 {
   foo<42l> f42; // <--- long constant, not int constant

   (void)f42; // avoid the "unused variable" warning
 }

我看到 clang++(8.0.0,例如)编译 g++(9.2.0,例如)给出以下错误的代码

prog.cc: In function 'int main()':
prog.cc:12:13: error: aggregate 'foo<42> f42' has incomplete type and cannot be defined
   12 |    foo<42l> f42;
      |             ^~~

如果我们使用 int 常量而不是 long 常量

,两个编译器都会编译
  foo<42>  f42;  // compile with both clang++ and g++

所以我有两个关于 C++ 语言层的问题

(1) 它是合法的,在 C++17 中,特化一个模板,声明接收一个 auto 模板参数,用于特定类型的值(作为我的 foo 特化代码)?

(2) 如果前面问题的答案是"yes",模板特化可以拦截不同(但可转换)类型的值?

问题(2)差不多:是对clang++还是g++?

这里有一个不依赖于不完整类型的稍微不同的重现:

template <auto> struct foo { static constexpr int value = 0; };
template <int I> struct foo<I> { static constexpr int value = 1; };

// ok on gcc, fires on clang which thinks foo<42L>::value is 1
static_assert(foo<42L>::value == 0);

这是一个 clang 错误。 42L 明显匹配 auto,毫无疑问。但是它匹配int I吗?不,来自 [temp.deduct.type]/19:

If P has a form that contains <i>, and if the type of i differs from the type of the corresponding template parameter of the template named by the enclosing simple-template-id, deduction fails. If P has a form that contains [i], and if the type of i is not an integral type, deduction fails. [ Example:

template<int i> class A { /* ... */ };
template<short s> void f(A<s>);
void k1() {
  A<1> a;
  f(a);             // error: deduction fails for conversion from int to short
  f<1>(a);          // OK
}


template<const short cs> class B { };
template<short s> void g(B<s>);
void k2() {
  B<1> b;
  g(b);             // OK: cv-qualifiers are ignored on template parameter types
}

end example ]

为了查看 42L 是否匹配专业化,我们需要从 42L 推导 int I 但失败了。因此,我们坚持主要专业化。 clang 不会这样做。归档 43076.