C++ Logo

std-discussion

Advanced search

Re: The issue about reference collapsing for function parameter pack

From: Andrew Schepler <aschepler_at_[hidden]>
Date: Sat, 5 Sep 2020 08:18:32 -0400
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_at_[hidden]> 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_at_[hidden]> 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]
>> <https://timsong-cpp.github.io/cppwp/n4659/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]
>> <https://timsong-cpp.github.io/cppwp/n4659/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]
>> <https://timsong-cpp.github.io/cppwp/n4659/dcl.ref#6>. So, I don't think
>> these rule is ok.
>>
>> Andrew Schepler <aschepler_at_[hidden]> 于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_at_[hidden]> 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_at_[hidden]
>> >> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>>
>

Received on 2020-09-05 07:22:14