1

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.

Artyer
  • 31,034
  • 3
  • 47
  • 75
  • How **clang** can deduce `Ui`===`Ti`? I tried with **MSVC**, it's same result as **gcc**. Looking at the definition of concept `same_as`, it is solved as `is_same_v && is_same_v` but **clang** uses an intrinsic in place `__is_same(Ti,Ui) && __is_same(Ui,Ti)`. I think it's why clang can deduce `Ui`===`Ti`. – dalfaB Jul 07 '23 at 15:21

1 Answers1

1

This looks like a GCC bug to me, it should be a pack expansion:

[temp.param]/17

... A type parameter pack with a type-constraint that contains an unexpanded parameter pack is a pack expansion. ...

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207