g ++和clang ++的行为不同,带有针对自动参数的模板专门化

max*_*x66 11 c++ template-specialization language-lawyer auto c++17

在使用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
 }
Run Code Online (Sandbox Code Playgroud)

我看到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;
      |             ^~~
Run Code Online (Sandbox Code Playgroud)

如果我们使用int常量而不是long常量,则两个编译器都将编译

  foo<42>  f42;  // compile with both clang++ and g++
Run Code Online (Sandbox Code Playgroud)

所以我对C ++语言层有两个问题

(1)在C ++ 17中,auto针对特定类型的值(如foo我的代码中的专门化),对声明接收了模板参数的模板进行专门化是合法的吗?

(2)如果对上一个问题的答案为“是”,则模板专业化可以拦截其他(但可转换)类型的值吗?

问题(2)几乎是:是clang ++还是g ++?

Bar*_*rry 7

这是一个略有不同的repro,它不依赖于不完整的类型:

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);
Run Code Online (Sandbox Code Playgroud)

这是一个lang虫。42L显然匹配auto,没有问题。但这匹配int I吗?不,来自[temp.deduct.type] / 19:

如果P具有包含的形式<i>,并且如果的类型i不同于由随附的simple-template-id命名的模板的相应模板参数的类型,则推论失败。如果P具有包含的形式[i],并且类型i为非整数,则推论失败。[ 示例:

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
}
Run Code Online (Sandbox Code Playgroud)

— 结束示例 ]

为了查看是否42L与专业匹配,我们需要从中推论 int I出42L,但失败了。因此,我们坚持主要的专业化。lang不这样做。提起43076。