Playing with C++17 auto
template arguments I've encountered another g++/clang++ disagreement.
Given the following simple code
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
}
I see that clang++ (8.0.0, by example) compile the code where g++ (9.2.0, by example) gives the following error
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;
| ^~~
Both compilers compile if we use a int
constant instead of a long
constant
foo<42> f42; // compile with both clang++ and g++
So I have two questions for C++ language layers
(1) it's legal, in C++17, specialize a template, declared receiving an auto
template parameter, for a value of a specific type (as the foo
specialization in my code)?
(2) if the answer to the preceding question is "yes", a template specialization can intercept a value of a different (but convertible) type?
Question (2) is almost: is right clang++ or g++?
Here's a slightly different repro that doesn't rely on incomplete types:
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);
This is a clang bug. 42L
clearly matches auto
, no question there. But does it match int I
? No, from [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 ]
In order to see if 42L
matches the specialization, we need to deduce int I
from 42L
and that fails. Hence, we stick with the primary specialization. clang does not do this. Filed 43076.