cplusplus / CWG

Core Working Group
23 stars 7 forks source link

[temp.arg.template] p3 Whether a template parameter pack that is a pack expansion is considered to be a pack after the instantiation of the enclosing template class #463

Open xmh0511 opened 8 months ago

xmh0511 commented 8 months ago

Full name of submitter (unless configured in github; will be published with the issue): Jim X

Consider this example:

#include <iostream>
#include <tuple>
template<class ...T>
struct A{
    template<template<T ...v> class...Tmpl>
    void fun(){
        using type = std::tuple<Tmpl<0>...>;
    }
};

template<int>
struct B{};

template<short>
struct C{};

int main(){
    A<int, int>{}.fun<B,C>();
}

[temp.arg.template] p3 says:

If P contains a template parameter pack, then A also matches P if each of A's template parameters matches the corresponding template parameter in the template-head of P. ... When P's template-head contains a template parameter pack ([temp.variadic]), the template parameter pack will match zero or more template parameters or template parameter packs in the template-head of A with the same type and form as the template parameter pack in P (ignoring whether those template parameters are template parameter packs).

Do we consider T... v as a template pack when checking this rule? If we do, how do we check whether the template parameters in B or C can match T... v?

Or, should we consider T... v as the result of the instantiation of the pattern of the pack expansion to check whether B matches Tmpl?

Suggested Resolution

GCC and Clang seem both cannot correctly compile this code, GCC rejected this case with the wrong reason, Clang is wrong to accept this example because template<int, int> class ...Tmpl(after the instantiation of the enclosing template class) cannot match template<int> class B, I think.

t3nsor commented 7 months ago

According to [temp.param]/17

[...] Similarly, a template parameter pack that is a type-parameter with a template-parameter-list containing one or more unexpanded packs is a pack expansion. [...]

This means that whenever the declaration of A<int, int>::fun gets instantiated, T ...v expands the unexpanded pack T. That means by the time you can start doing overload resolution with A<int, int>::fun, its template parameter list looks like template <int, int> class... Tmpl.

I don't see any need for a wording change here. If a compiler has a bug, please report it to the developers.