Date: Tue, 15 Nov 2022 15:57:54 +0000
On Tue, 15 Nov 2022 at 15:43, Arthur O'Dwyer via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> On Mon, Nov 14, 2022 at 1:08 PM Anoop Rana <ranaanoop986_at_[hidden]> wrote:
>
>> > Ts=<int,int>, Us=<> , but as far as I could tell, Anoop rejects that
>> outcome.
>>
>> Note that I don't actually reject `Ts={int, int}`, `Us={ }`. What I am
>> objecting is that the program 1.1 is ill-formed *with `U` not being { } *as
>> per the current wording instead of being
>>
>> *1)* well-formed with `Ts={int, int}`, `Us={ }` assuming packs are
>> greedy(no ambiguity) or
>> *2) *ill-formed with `Ts={int, int}`, `Us={ }` assuming this is
>> ambiguous instead of being greedy or
>> *3) *ill-formed with `Ts={int, int}`, `Us={}` assuming packs are
>> greedy(no ambiguity). If this point 3 is what the standard currently
>> supports then it doesn't make sense because a parameter pack is allowed to
>> be empty so that Ts={int, int}, Us={ } is an expected output and the
>> program should be well-formed instead of ill-formed. Note again that
>> Ts={int, int}, Us={ } is an expected output in this point 3 because there
>> is no ambiguity interpretation used here in this point. These
>> interpretations are separate from each other as also noted below.
>>
>
> I think your classification into 1,2,3 doesn't make sense; but I've also
> just realized that I was wrong about the current state of affairs.
>
> template<class... Ts, class... Us> void f();
> f<int,int>();
>
> is actually accepted today by both GCC and Clang (deducing Ts={int,int},
> Us={}).
> MSVC rejects the template declaration of `f` itself (even before it's ever
> called) with a hard error. I think MSVC's behavior is what the Standard
> strictly requires.
>
Yes, this is https://eel.is/c++draft/temp.param#14
It would be worth exploring to what extent the proposal here is affected if
some of the packs can be deduced from function template arguments (etc.).
> But this is highly relevant to your paper, because "Let's change the rules
> that everyone currently follows" is a harder sell than "Let's change the
> rules that 2/3 of vendors don't follow anyway." And ideally you'd be saying
> "Let's change the rules to *the thing that 2/3 of vendors already do*"
> (i.e., "standardize existing practice"). I don't think that's actually
> what you're saying, but, maybe it should be?
>
> As before, the paper lacks actual motivation for why a working programmer
> would want this change (or any change in this area). The proposal increases the
> number of paint splotches that are valid C++ programs
> <https://www.mcmillen.dev/sigbovik/2019.pdf>, but what is the *actual*
> benefit to a human C++ programmer?
>
> Instead of spreading out your "before/after comparison" section vertically
> over three pages, I suggest you make a little table something like this:
>
>
> |----------------------------------------------------------|-----------------|-----|-------|------|------|----------|
>
> | Template | Usage
> | GCC | Clang | MSVC | EDG | Standard |
>
>
> |----------------------------------------------------------|-----------------|-----|-------|------|------|----------|
>
> | template<class... Ts, class... Us> int f1(); |
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, class... Us> int f1(); | f1<int, int>
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, int... Us> int f2(); |
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, int... Us> int f2(); | f2<int, 1>
> | Err | Err | Err | Err | Err |
>
> | template<class... Ts, int U> int f3(); |
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, int U> int f3(); | f3<int, 1>
> | Err | Err | Err | Err | Err |
>
> | template<class... Ts, template<class> class U> int f4(); |
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, template<class> class U> int f4(); | f4<int, C>
> | Err | Err | Err | Err | Err |
>
> | template<class... Ts, int U, class... Vs> int f5(); |
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, int U, class... Vs> int f5(); | f5<int, 1>
> | Err | Err | Err | Err | Err |
>
> | template<class... Ts, int U, class... Vs> int f5(); | f5<1, int>
> | Err | Err | Err | Err | Err |
>
> | template<class... Ts, int U, class... Vs> int f5(); | f5<int, 1,
> int> | Err | Err | Err | Err | Err |
>
> | template<class... Ts, int... Us, class... Vs> int f6(); |
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, int... Us, class... Vs> int f6(); | f6<int>
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, int... Us, class... Vs> int f6(); | f6<int, int>
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, int... Us, class... Vs> int f6(); | f6<int, 1>
> | Err | Err | Err | Err | Err |
>
> | template<class... Ts, int... Us, class... Vs> int f6(); | f6<int, 1,
> int> | Err | Err | Err | Err | Err |
>
> | template<auto... Ts, int... Us> int f7(); |
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<auto... Ts, int... Us> int f7(); | f7<1>
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<auto... Ts, int... Us> int f7(); | f7<&i, 1>
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<int... Ts, auto... Us> int f8(); |
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<int... Ts, auto... Us> int f8(); | f7<1>
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<int... Ts, auto... Us> int f8(); | f7<&i>
> | Err | Err | Err | Err | Err |
>
> | template<same_as<char> auto... Ts, same_as<int> auto... Us> int f9(); |
> | ✓ | ✓ | Err | Unsupp | Err |
>
> | template<same_as<char> auto... Ts, same_as<int> auto... Us> int f9(); |
> f9<1> | Err | Err | Err | Unsupp | Err |
>
> | template<same_as<char> auto... Ts, same_as<int> auto... Us> int f9(); |
> f9<'x', 1> | Err | Err | Err | Unsupp | Err |
>
> and then add another column on the end, "Proposed," with what you propose
> for each case.
>
> *NOTE:*
>> Just to sum up some things, according to the paper `template<typename...
>> T, typename... U> f(){}` is ill-formed because `U` and `T` have the same
>> underlying types(meaning they both are "type" parameter packs)
>>
>
> FWIW, I'd say "the same kind" rather than "the same underlying type," as
> the latter has a technical meaning already.
> I'd like to see an example where the parser's kind-disambiguation rules
> come into play, like
> constexpr double PI = 3.14; // red herring
> template<char... Ts, class... Us> int f10(); // currently ill-formed,
> proposed OK
> f10<char{}>(); // proposed OK with Ts={0} Us={}
> f10<char()>(); // proposed OK with Ts={} Us={char()}
> f10<char(int(3.14))>(); // proposed OK with Ts={3} Us={}
> f10<char(int(PI))>(); // proposed OK with Ts={} Us={char(int)}
>
> A procedural note: You've labeled your mailing-list drafts PxxxxR0 and
> PxxxxR1. You should instead label them DxxxxR0 (draft revision 0) and
> DxxxxR0 (draft revision 1), and so on. When (if) you submit the paper to an
> actual mailing, you'll number *that submission* as PxxxxR0, and then
> start working on new drafts as DxxxxR1 (draft revision whatever).
>
> HTH,
> Arthur
>
>> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
std-proposals_at_[hidden]> wrote:
> On Mon, Nov 14, 2022 at 1:08 PM Anoop Rana <ranaanoop986_at_[hidden]> wrote:
>
>> > Ts=<int,int>, Us=<> , but as far as I could tell, Anoop rejects that
>> outcome.
>>
>> Note that I don't actually reject `Ts={int, int}`, `Us={ }`. What I am
>> objecting is that the program 1.1 is ill-formed *with `U` not being { } *as
>> per the current wording instead of being
>>
>> *1)* well-formed with `Ts={int, int}`, `Us={ }` assuming packs are
>> greedy(no ambiguity) or
>> *2) *ill-formed with `Ts={int, int}`, `Us={ }` assuming this is
>> ambiguous instead of being greedy or
>> *3) *ill-formed with `Ts={int, int}`, `Us={}` assuming packs are
>> greedy(no ambiguity). If this point 3 is what the standard currently
>> supports then it doesn't make sense because a parameter pack is allowed to
>> be empty so that Ts={int, int}, Us={ } is an expected output and the
>> program should be well-formed instead of ill-formed. Note again that
>> Ts={int, int}, Us={ } is an expected output in this point 3 because there
>> is no ambiguity interpretation used here in this point. These
>> interpretations are separate from each other as also noted below.
>>
>
> I think your classification into 1,2,3 doesn't make sense; but I've also
> just realized that I was wrong about the current state of affairs.
>
> template<class... Ts, class... Us> void f();
> f<int,int>();
>
> is actually accepted today by both GCC and Clang (deducing Ts={int,int},
> Us={}).
> MSVC rejects the template declaration of `f` itself (even before it's ever
> called) with a hard error. I think MSVC's behavior is what the Standard
> strictly requires.
>
Yes, this is https://eel.is/c++draft/temp.param#14
It would be worth exploring to what extent the proposal here is affected if
some of the packs can be deduced from function template arguments (etc.).
> But this is highly relevant to your paper, because "Let's change the rules
> that everyone currently follows" is a harder sell than "Let's change the
> rules that 2/3 of vendors don't follow anyway." And ideally you'd be saying
> "Let's change the rules to *the thing that 2/3 of vendors already do*"
> (i.e., "standardize existing practice"). I don't think that's actually
> what you're saying, but, maybe it should be?
>
> As before, the paper lacks actual motivation for why a working programmer
> would want this change (or any change in this area). The proposal increases the
> number of paint splotches that are valid C++ programs
> <https://www.mcmillen.dev/sigbovik/2019.pdf>, but what is the *actual*
> benefit to a human C++ programmer?
>
> Instead of spreading out your "before/after comparison" section vertically
> over three pages, I suggest you make a little table something like this:
>
>
> |----------------------------------------------------------|-----------------|-----|-------|------|------|----------|
>
> | Template | Usage
> | GCC | Clang | MSVC | EDG | Standard |
>
>
> |----------------------------------------------------------|-----------------|-----|-------|------|------|----------|
>
> | template<class... Ts, class... Us> int f1(); |
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, class... Us> int f1(); | f1<int, int>
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, int... Us> int f2(); |
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, int... Us> int f2(); | f2<int, 1>
> | Err | Err | Err | Err | Err |
>
> | template<class... Ts, int U> int f3(); |
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, int U> int f3(); | f3<int, 1>
> | Err | Err | Err | Err | Err |
>
> | template<class... Ts, template<class> class U> int f4(); |
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, template<class> class U> int f4(); | f4<int, C>
> | Err | Err | Err | Err | Err |
>
> | template<class... Ts, int U, class... Vs> int f5(); |
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, int U, class... Vs> int f5(); | f5<int, 1>
> | Err | Err | Err | Err | Err |
>
> | template<class... Ts, int U, class... Vs> int f5(); | f5<1, int>
> | Err | Err | Err | Err | Err |
>
> | template<class... Ts, int U, class... Vs> int f5(); | f5<int, 1,
> int> | Err | Err | Err | Err | Err |
>
> | template<class... Ts, int... Us, class... Vs> int f6(); |
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, int... Us, class... Vs> int f6(); | f6<int>
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, int... Us, class... Vs> int f6(); | f6<int, int>
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<class... Ts, int... Us, class... Vs> int f6(); | f6<int, 1>
> | Err | Err | Err | Err | Err |
>
> | template<class... Ts, int... Us, class... Vs> int f6(); | f6<int, 1,
> int> | Err | Err | Err | Err | Err |
>
> | template<auto... Ts, int... Us> int f7(); |
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<auto... Ts, int... Us> int f7(); | f7<1>
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<auto... Ts, int... Us> int f7(); | f7<&i, 1>
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<int... Ts, auto... Us> int f8(); |
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<int... Ts, auto... Us> int f8(); | f7<1>
> | ✓ | ✓ | Err | Warn | Err |
>
> | template<int... Ts, auto... Us> int f8(); | f7<&i>
> | Err | Err | Err | Err | Err |
>
> | template<same_as<char> auto... Ts, same_as<int> auto... Us> int f9(); |
> | ✓ | ✓ | Err | Unsupp | Err |
>
> | template<same_as<char> auto... Ts, same_as<int> auto... Us> int f9(); |
> f9<1> | Err | Err | Err | Unsupp | Err |
>
> | template<same_as<char> auto... Ts, same_as<int> auto... Us> int f9(); |
> f9<'x', 1> | Err | Err | Err | Unsupp | Err |
>
> and then add another column on the end, "Proposed," with what you propose
> for each case.
>
> *NOTE:*
>> Just to sum up some things, according to the paper `template<typename...
>> T, typename... U> f(){}` is ill-formed because `U` and `T` have the same
>> underlying types(meaning they both are "type" parameter packs)
>>
>
> FWIW, I'd say "the same kind" rather than "the same underlying type," as
> the latter has a technical meaning already.
> I'd like to see an example where the parser's kind-disambiguation rules
> come into play, like
> constexpr double PI = 3.14; // red herring
> template<char... Ts, class... Us> int f10(); // currently ill-formed,
> proposed OK
> f10<char{}>(); // proposed OK with Ts={0} Us={}
> f10<char()>(); // proposed OK with Ts={} Us={char()}
> f10<char(int(3.14))>(); // proposed OK with Ts={3} Us={}
> f10<char(int(PI))>(); // proposed OK with Ts={} Us={char(int)}
>
> A procedural note: You've labeled your mailing-list drafts PxxxxR0 and
> PxxxxR1. You should instead label them DxxxxR0 (draft revision 0) and
> DxxxxR0 (draft revision 1), and so on. When (if) you submit the paper to an
> actual mailing, you'll number *that submission* as PxxxxR0, and then
> start working on new drafts as DxxxxR1 (draft revision whatever).
>
> HTH,
> Arthur
>
>> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
Received on 2022-11-15 15:58:07