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.
使用 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 ofi
differs from the type of the corresponding template parameter of the template named by the enclosing simple-template-id, deduction fails. IfP
has a form that contains[i]
, and if the type ofi
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.