Look at this simple snippet:
enum class Enum1 { Value };
enum class Enum2 { Value };
template <auto> struct Foo;
template <> struct Foo<Enum1::Value> { };
template <> struct Foo<Enum2::Value> { };
Clang compiles this, but gcc-7.2 fails:
x.cpp:5:20: error: redefinition of ‘struct Foo<(Enum1)0>’ template <> struct Foo { };
This error message seems invalid, as at line 5, Enum2::Value
is written.
Which compiler is correct? Is this conforming code?
In [dcl.type.auto.deduct]:
A type
T
containing a placeholder type, and a corresponding initializere
, are determined as follows:
- for a non-type template parameter declared with a type that contains a placeholder type,
T
is the declared type of the non-type template parameter ande
is the corresponding template argument.
This seems to suggest that the deduced type would be decltype(Enum1::Value)
, and the value would be Enum1::Value
.
Is decltype(Enum1::Value)
equal to decltype(Enum2::Value)
? This code...
static_assert(std::is_same_v<decltype(Enum1::Value), decltype(Enum2::Value)>);
...fails to compile with both clang++ 6 and g++ 8.
I think that you might have exposed a bug in gcc. As Johannes Schaub pointed out in the comments, there's also a paragraph in favour of gcc's behavior.
There's a bug report open: #79092.
Also note that the following code is accepted by both compilers:
template <typename T, T> struct Foo;
template <> struct Foo<decltype(Enum1::Value), Enum1::Value> { };
template <> struct Foo<decltype(Enum2::Value), Enum2::Value> { };
template <auto>
behaving differently from that would be (IMHO) suprising and undesired.
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