I think the Standard is okay here.

The name T of the template parameter pack certainly isn't a typedef-name: we can't have "T var;" or "T&& var;". It's only inside a pack expansion where T should obey this rule, as in (T&&... args) in this example, or std::tuple<T&&...> var;, or etc.

And I think the rules for instantiating pack expansions in [temp.variadic] do qualify T inside an expansion for the reference collapsing rule.

  • In a template parameter pack that is a pack expansion ([temp.param]):
    • if the template parameter pack is a type-parameter; the pattern is the corresponding type-parameter without the ellipsis.

The instantiation of a pack expansion that is neither a sizeof... expression nor a fold-expression produces a list of elements E_1, E_2, ..., E_N, where N is the number of elements in the pack expansion parameters. Each E_i is generated by instantiating the pattern and replacing each pack expansion parameter with its i-th element. Such an element, in the context of the instantiation, is interpreted as follows:
  • if the pack is a template parameter pack, the element is a template parameter ([temp.param]) of the corresponding kind (type or non-type) designating the i-th corresponding type or value template argument;
So when the template parameter pack is instantiated in func<int, char>, the pattern is "typename T", then T is replaced with the invented type template parameters E_i. We can either interpret "its identifier" for such a parameter E_i to be the T in the pattern, or consider each E_i to act as if it has a unique unspellable identifier since it replaces T. Either way the identifier does not follow an ellipsis, so E_i is a typedef-name.

On Wed, Sep 2, 2020 at 8:49 AM jim x via Std-Discussion <std-discussion@lists.isocpp.org> wrote:
About the reference collapsing, its rule is defined as the  following:  

>If a typedef-name ([dcl.typedef], [temp.param]) or a decltype-specifier denotes a type TR that is a reference to a type T, an attempt to create the type “lvalue reference to cv TR” creates the type “lvalue reference to T”, while an attempt to create the type “rvalue reference to cv TR” creates the type TR.  

However, consider such a case:  
void func(T&&...args){
int main(){
   int a{};
   char b{};
we know the deduced template argument are `int&` and `char&`. That is, the function type is void(int&,char&). we know the reference collapsing rules is applying for this case. However, I have to say that the identifier `T` is neither a typedef-name nor decltype-specifier, because of the following rule:      

A type-parameter whose identifier does not follow an ellipsis defines its identifier to be a typedef-name (if declared without template) or template-name (if declared with template) in the scope of the template declaration.   

So, these rules are contradicting with each others. How to interpret this? Is it a defect in the standard?
Std-Discussion mailing list