I have a template-head of the form template<C<T>... U>
, where C
is a concept and T
is a pack of types. U
will have to be its own pack, but how exactly is this parsed?
For example https://godbolt.org/z/MhG9YqsdK:
#include <concepts>
template<typename... T>
struct F {
template<std::same_as<T>... U>
static void f(U... args, void*);
};
int main() {
F<int, char>::f(1, 'x', nullptr);
}
I would think that std::same_as<T>
is a pattern for an expansion, so this expands to two template arguments, like:
template<>
struct F<int, char> {
template<std::same_as<int> U0, std::same_as<char> U1>
static void f(U0 arg0, U1 arg1, void*);
};
Which is what clang seems to do. What gcc seems to do is transform it like:
template<typename... T>
struct F {
template<typename... U> requires (std::same_as<U, T> && ...)
static void f(U... args, void*);
};
which makes U
a new pack in a non-deduced context (And a SFINAE error when U
can't be deduced and is an empty pack and T
isn't).
Which compiler is correct? I would assume [temp.variadic]p5 is what I am looking for if this was actually a pack expansion, but I'm not sure if it applies. I also can't find where in the standard constrained variadic parameter packs are defined to see if gcc's behaviour is correct.
This looks like a GCC bug to me, it should be a pack expansion:
... A type parameter pack with a type-constraint that contains an unexpanded parameter pack is a pack expansion. ...