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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With