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:12:21 -0400
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:16:09