Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it allowed to specialize a template with enums with the same integral value?

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?

like image 943
geza Avatar asked Oct 25 '17 12:10

geza


1 Answers

In [dcl.type.auto.deduct]:

A type T containing a placeholder type, and a corresponding initializer e, 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 and e 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.

like image 96
Vittorio Romeo Avatar answered Nov 15 '22 19:11

Vittorio Romeo