Specializing template with integer_sequence. GCC vs MSVC

Viewed 69

So, I came across a piece of code that behaves differently in GCC and MSVC:

#include <utility>

typedef int IType;

template<typename> struct A;

template<int... Ns>
struct A<std::integer_sequence<IType, Ns...>> {
    using type = bool; 
};

using B = typename A<std::make_integer_sequence<IType, 3>>::type;

int main() {
    B b;
}

This happily compiles on both compilers. However, if you define IType as typedef long IType; MSVC still works whereas GCC says:

source>:12:61: error: invalid use of incomplete type 'struct A<std::integer_sequence<long int, 0, 1, 2> >'

   12 | using B = typename A<std::make_integer_sequence<IType, 3>>::type;

      |                                                             ^~~~

<source>:5:27: note: declaration of 'struct A<std::integer_sequence<long int, 0, 1, 2> >'

    5 | template<typename> struct A;

      |                           ^

<source>: In function 'int main()':

<source>:15:3: error: 'B' was not declared in this scope

   15 |   B b;

      |   ^

Compiler returned: 1

So, obviously when IType is long GCC fails to use the 2nd more specialized definition of A and thus fails. I'm really struggling to understand why int and long are treated differently by GCC here.

I used GCC 10.1 and MSVC 19.24 in Compiler Explorer to play with it. https://godbolt.org/z/7L3xap

1 Answers

std::integer_sequence is defined as

template< class T, T... Ints >
class integer_sequence;

That is, the type of the values is T.

So when changing IType to long, also the type of Ns... should be changed to long...:

typedef int IType;

template<typename> struct A;

template<IType... Ns>  // <--- HERE
struct A<std::integer_sequence<IType, Ns...>> {
    using type = bool; 
};

Otherwise you get a specialization of struct A<long, int, int, int> which won't match struct A<long, long, long, long> (MSVC seems to be more lenient on this, but GCC behavior is more correct IMO).

Related