Andrew Schepler <aschepler@gmail.com> 于2020年9月7日周一 下午10:24写道:
On Sun, Sep 6, 2020 at 10:01 AM jim x <xmh970252187@gmail.com> wrote:
... 
"typename...T" is not a pack expansion, so  [temp.variadic#7]  can't apply to this declaration which declare a template parameter pack. 

Aha, I missed that. So yes, I guess this is an issue. When the pack expansion "T&& ...args" is instantiated, clause [temp.variadic]/7 does say T is replaced with a template type parameter in each element of the function parameter list. We would like to say that every template type parameter (which is not a template template parameter) is always a typedef-name. But since this template parameter was invented for the variadic template instantiation, either it has no declaration in the source and no identifier for [temp.param]/3 to apply to, or else "its identifier" is the "T" in "typename... T", which as you point out does not make it a typedef-name.

I'll also retract my very first statement, "The name T of the template parameter pack certainly isn't a typedef-name". I'm not really sure now why the wording about the ellipsis is even there in [temp.param]/3. A non-type template parameter doesn't need it, as [temp.param]/6 says simply "A non-type non-reference template-parameter is a prvalue" without consideration for an ellipsis or template parameter pack. When looking at just the template declaration, we don't know how many template parameters an instantiation of a template parameter pack will have, but that's very much like not knowing what the actual aliased type, aliased template, referenced entity, or constant expression value will be for a non-pack template parameter. This doesn't need to stop the pack's name from being a typedef-name, template-name, lvalue, or prvalue. As far as needing to actually be expanded, that's a separate rule (specifically, in [temp.variadic]/6).
 
And for this [temp.param#3] rule, I have a different understanding with yours, 
>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. [ Note: A template argument may be a class template or alias template.  

This rule is totally about the parameter declaration. In other words, `template<typename T>` where identifier  `T` is defined as a typedef-name. Conversely, For the form `template<typename...T>` , where T is not defined as a typedef-name, because such declaration does not satisfy what the above rule says, that is " A type-parameter whose identifier does not follow an ellipsis defines its identifier to be a typedef-name (if declared without template)". So, wherever such an identifier appear in, such an identifier can't be considered as a typedef-name(it's determined by the declaration where such a identifier appears). Such as, for this declaration `typedef int Integer`, `Integer` is a typedef-name whatever the form where the such a name appears.(Because the declaration declare such a name as a typedef-name). But, I'm not 100% sure the exactly intent of  [temp.param#3] is not what you said, I have to say whether a name has a property or not is determined by its declaration which introduced the name and such a property appertains to such a name , whatever how to use this name.  


I think, because a template parameter pack(type-parameter) is a collection  of various types, and since a typedef-name can only denote one type, so [temp.param#3] should cover such a case and point out such a pack name is not to be considered as a typedef-name. Maybe as you said, [temp.variadic#7.1] describes how to instantiate the pattern when the pack is a template parameter pack. IIUC, for a function parameter pack declaration, that is `T&&...args`, the pattern should be `T&& args`, where the pack expansion parameter `T` is replaced by these elements in the  collection of pack expansion parameters, these elements as said in  [temp.variadic#7.1], which are template parameter of the corresponding kind, maybe the corresponding template parameter declaration will be invented for these template parameter which will be used to replace the pack expansion parameter(which would be like `template<typename template-parameter-1, typename template-parameter-2,..., typename template-parameter-n>`), so these invented template parameter declarations satisfy the form says in [temp.param#3], which are typedef-name. In addition, although the standard does not give a definition for `pack expansion parameter`, we infer that such a stuff is the parameter appears in a pattern, that is the pack name.  


Andrew Schepler <aschepler@gmail.com> 于2020年9月5日周六 下午8:18写道:
Oh, I think I missed a key point in your reading.

such as, the deduced template argument is `int&` when I pass a lvalue of type `int` as the unique argument, that means, the collection of `pack expansion parameters` only has one element which is `int&`,

In the instantiation of "T&& ...args" when the template argument list is ("int&"), the parameter T is not replaced with the template argument "int&". It is replaced with the first (only) template parameter formed by the instantiation of "<typename... T>". That template parameter is a typedef-name which aliases int&.

On Sat, Sep 5, 2020 at 8:12 AM Andrew Schepler <aschepler@gmail.com> wrote:
Hi again Jim,

It is the declaration of a template type parameter, not any of its uses, which makes it a typedef-name. Note the quoted 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." is [temp.param]/3, and [temp.param] is entirely about interpretation of the template parameters which appear in a "template <template-parameter-list>" syntax.

Taking the packs out of the picture, in

template <typename T>
void func2(T&& arg) {}

the identifier which does not follow an ellipsis is just the first appearance of T, in the parameter declaration. Since it does not, T becomes a typedef-name in the scope of the template; in particular, where it is named in "T&& arg". 

(Even if the rule did apply to the function parameter pack "T&& ...args", the identifier of the type-parameter is still T, not args, and T does not "follow an ellipsis" in this syntax at all.)

Andrew Schepler


On Sat, Sep 5, 2020 at 4:33 AM jim x <xmh970252187@gmail.com> wrote:
Hi, Andrew Schepler.  

Maybe you misread these rules. For my example, namely `T&&...args`, the pack expansion occurs in a function parameter pack, that is said, the rule [temp.variadic#4.1] applies to this example.
That means, "the pattern is the parameter-declaration without the ellipsis."(namely T&& args) . In addition, what the exactly meaning of "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... if the pack is a template parameter pack" is that, for  `T&&...args` where `T` is a template parameter pack, it's a pack expansion. As aforementioned , the pattern for `T&&...args` is `T&& args`, such form is the pattern for `Ei` which would be generated  by instantiating  such a pattern. Note though, this sentence "and replacing each pack expansion parameter with its i-th element.", that means, the element is the corresponding value of the template parameter as said in [temp.variadic#7.1].  such as, the deduced template argument is `int&` when I pass a lvalue of type `int` as the unique argument, that means, the collection of `pack expansion parameters` only has one element which is `int&`, and such a element is used to replace the corresponding pack expansion parameter which is a component of the pattern. So the result of such an instantiation of the pattern would be `int&&& args1`(hypothetical form), then the reference collapsing should be performed for such a declaration. However within this hypothetical declaration,  `int&` is neither a typedef-name or  decltype-specifier.  It violates the rule [dcl.ref#6]. So, I don't think these rule is ok.

Andrew Schepler <aschepler@gmail.com> 于2020年9月4日周五 下午6:43写道:
>
> 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.
>
> [temp.variadic]/(5.3):
>>
>> 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.
>
>
> [temp.variadic]/8:
>>
>> 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:  
>> ````
>> template<typename...T>
>> void func(T&&...args){
>> }
>> int main(){
>>    int a{};
>>    char b{};
>>    func(a,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
>> Std-Discussion@lists.isocpp.org
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion