'Compiler discrepencies in deduction of template parameter of nested alias template

Consider the following code snippet where we we're trying to deduce the template parameter to the function foobar():

struct Bar { static constexpr auto size = 5; };

template <class T, class=std::make_index_sequence<T::size>>
struct FooList;
template <class T, std::size_t... Idxs>
struct FooList<T, std::integer_sequence<std::size_t, Idxs...>> { };

struct Wrapper {
  template <class T>
  using list_type = FooList<T>;
};

template <class T>
void foobar(typename Wrapper::template list_type<T>) { }

void test() { 
  foobar(FooList<Bar>{});
}

The major compiler frontends disagree on whether this should compile (see this godbolt). If we give the template parameter explicitly, like this:

void test_explicit() { 
  foobar<Bar>(FooList<Bar>{});
}

all of the major frontends compile the code successfully (godbolt). Interestingly, if we make the deduction simpler:

struct Bar { };

struct Wrapper {
  template <class T>
  using my_type = T;
};

template <class T>
void foobar(typename Wrapper::template my_type<T>) { }

void test() { 
  foobar(Bar{});
}

a different subset of the frontends compile and fail to compile (MSVC being the only one that compiles both, see this godbolt).

Which implementation is conforming here, and which are buggy (and why)? Can anyone find the portion of the C++ standard that specifies how this should work?



Solution 1:[1]

As discussed in the comments, this is a clang bug in the implementation of __make_integer_seq. I wanted to offer a workaround:

#include <utility>

namespace workaround {
#ifdef __clang__
  template<class T, T N>
  struct make_index_sequence_helper {
      using type = __make_integer_seq<std::integer_sequence, T, N>;
  };

  template<class T, T N>
  using make_integer_sequence = typename make_index_sequence_helper<T, N>::type;

  template<std::size_t N>
  using make_index_sequence = make_integer_sequence<std::size_t, N>;
#else
  using std::make_integer_sequence;
  using std::make_index_sequence;
#endif
}

Then using it in FooList works again:

template <class T, class=workaround::make_index_sequence<T::size>>
struct FooList;
template <class T, std::size_t... Idxs>
struct FooList<T, std::integer_sequence<std::size_t, Idxs...>> { };

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1