Date: Fri, 30 Sep 2022 17:38:38 +0100
Hi,
One more syntax proposal that extends P1985's unkiversal template parameter: `template auto`
1. allow `template auto` in any deduced context, for example `vector<template auto> vec = get_vec();`
2. use the syntax `template<class T> auto` to introduce the name `T`.
template<class T> auto x = foo()
vector<template<class V> auto> v = get_vec()
Some extra stuff:
* Introducing a name is optional, you can use `template<class> auto` for a type placeholder, instead of a universal one
* you can have nttp or template placeholders too
std::array<string, template<size_t arr_size> auto> arr = get_arr();
A bit verbose compared to my previously proposed auto<class T>. Honestly, I like that more, but I could live with this.
I definitely wouldn't want a syntax where you are required to immediately repeat the introduced name.
Cheers,
Lénárd
On 30 September 2022 15:01:58 BST, Edward Catmur via Std-Proposals <std-proposals_at_[hidden]> wrote:
>On Fri, 30 Sept 2022 at 14:19, Oleksandr Koval <
>oleksandr.koval.dev_at_[hidden]> wrote:
>
>> Sorry if this was already discussed, I like `auto<class T>` syntax but the
>> problem I see is this:
>>
>> std::vector<int> f();
>> auto<class T> v = f(); // should T be `std::vector<int>` or just `int`?
>>
>
>That syntax would work as a 2-step process: first you declare entities,
>then deduce them. The declaration and deduction should be pretty much the
>same as for (non-terse) function templates.
>
>So T is repeated:
>
>auto<class T> T v = f();
>
>or
>
>auto<class T> std::vector<T> v = f();
>
>or
>
>auto<template<class> class TT, class T> TT<T> v = f();
>
>
>It’s a bit confusing when you see them side by side. Because of that I
>> don’t think that using angle brackets is a good idea (at least I can’t find
>> any form which is not confusing). We need a new syntax which will clearly
>> show that typename(s) is closely related to `auto` itself. For example:
>>
>> auto:[class T] v = f();
>> auto:[class T1, classT2] [key, value] = get_pair();
>>
>> On Fri, Sep 30, 2022 at 4:07 AM Edward Catmur via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>>>
>>>
>>> On Thu, 29 Sept 2022 at 21:44, Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
>>> wrote:
>>>
>>>> On Thu, Sep 29, 2022 at 3:57 PM Lénárd Szolnoki via Std-Proposals <
>>>> std-proposals_at_[hidden]> wrote:
>>>>
>>>>> On 29 September 2022 20:25:06 BST, Edward Catmur <
>>>>> ecatmur_at_[hidden]> wrote:
>>>>> >On Thu, 29 Sept 2022 at 18:15, Lénárd Szolnoki via Std-Proposals <
>>>>> std-proposals_at_[hidden]> wrote:
>>>>> >
>>>>> >> I think this could be addressed by two distinct proposals.
>>>>> >>
>>>>> >> 1. allow placeholders to appear in any deduced context
>>>>> (std::vector<auto>)
>>>>> >> 2. allow a placeholder to introduce a name (auto<class T>, auto<int
>>>>> i>
>>>>> >> might appear as a deduced nttp)
>>>>> >>
>>>>> >> Then you can have your vector<auto<class T>> to deduce the value
>>>>> type and
>>>>> >> introduce the name T for that.
>>>>> >
>>>>> >std::vector<auto> is problematic, because elsewhere auto means a value
>>>>> of
>>>>> >unconstrained type (e.g. in template<auto>).
>>>>>
>>>>> I disagree. auto is a placeholder for the type of the non-type
>>>>> parameter. If you don't omit the name, then that name refers to the value.
>>>>>
>>>>
>>>> FWIW, I tend to agree with Lénárd here: `auto *p, std::unique_ptr<auto>
>>>> q` seems quite reasonable to me.
>>>>
>>>
>>> Ye-esss; looking at the grammar; `auto` is always a
>>> placeholder-type-specifier, which is a simple-type-specifier, so it makes
>>> sense that it takes the place of a concrete (or inferred) type.
>>>
>>> So Lénárd, I apologise; you're correct that in these contexts `auto`
>>> designates a type, not a value. I'm still trying to get my head round
>>> "template<auto> int f();", but the syntax is clear.
>>>
>>> *However*, I foresee practical problems with allowing auto *anywhere* in
>>>> a declaration. Consider
>>>> template<class T> void f(T t); // since C++98
>>>> template<class T> void g(decltype(T(1)) t); // since C++11
>>>> void f(auto t); // since C++20, equivalent to f #1
>>>> void g(decltype(auto(1)) t); // since C++23, *not* equivalent to g
>>>> #1
>>>>
>>>> Now, the `T` parameter to `g` is not deducible, so "obviously" the
>>>> `auto` in g #2 doesn't mean the same thing as the `auto` in f #2. But are
>>>> you sure we can teach that to the computer?
>>>>
>>>> (Background: I teach that `auto` since C++14 has (like most C++
>>>> keywords) had two meanings: concrete type *inference*, as in auto x =
>>>> 1, and templatey type *deduction*, as in [](auto x){}. The physical
>>>> mechanisms behind, and consequences of, these two usages of `auto` are
>>>> vastly different, although their human-level meaning is similar: "I don't
>>>> want to bother with types; compiler, please figure it out." So if you see
>>>> me talking about "inference" versus "deduction," or "the first meaning of
>>>> auto" versus "the second meaning of auto," that's what I'm talking about.)
>>>>
>>>
>>> The deduction process is ultimately the same; both end up in
>>> temp.deduct.call. In an abbreviated function template or generic lambda,
>>> the deduction can be overridden by explicit template argument, but that's a
>>> relatively minor effect. And syntactically, they're the same; a
>>> decl-specifier of a decl-specifier-seq (of a function parameter or variable
>>> declaration); `auto` in a function return type or trailing return type has
>>> less in common, though I'd suppose you'd class that as inference. Still, I
>>> guess it's OK to teach it that way.
>>>
>>> It would certainly *not* be reasonable to have a rule like "Try to
>>>> interpret every `auto` as deduction, but if that would result in a
>>>> non-deducible template parameter, then backtrack and assume it's inference
>>>> instead." It would be reasonable to have a rule that boils down to "Inside
>>>> the operand of a decltype or sizeof or array bound, the `auto` always means
>>>> inference not deduction." But is `g` above the *only* problem case?
>>>> Are there other corner cases where `auto` is already legal today, and/or we
>>>> wouldn't want it to mean a template parameter?
>>>> void f(A<auto(int())>); // is this concrete A<0> or templatey
>>>> A<T(int())>? I guess the type of A will disambiguate...
>>>>
>>>
>>> Currently a placeholder can appear as the decl-specifier of a function
>>> parameter, variable declaration, or template parameter or, as exactly one
>>> simple-type-specifier of a return or trailing return type,
>>> conversion function id, new expression's type id, or (`auto` only) as the
>>> type specifier of a functional cast. If these were relaxed, I think we'd
>>> probably be OK; you just go through inventing extra type template
>>> parameters and perform deduction as usual.
>>>
>>> Also I don't think ambiguity *can* be an issue, or it would be already;
>>> there must be disambiguators in the syntax. Indeed, I have a strong
>>> suspicion that your `A<auto(int())>` is a most vexing parse.
>>>
>>> Also consider that while
>>>> void h1(std::vector<auto, auto> v);
>>>> would work fine with Lénárd's proposed syntax,
>>>> void h2(std::array<auto, ??> a);
>>>> would not. That does seem mildly problematic. However, maybe it's
>>>> consistent with C++20, which permits
>>>> template<class T> concept Integral = true;
>>>> template<Integral T> void ij(); // since C++20
>>>> but not
>>>> template<int N> concept Odd = true;
>>>> template<Odd N> void ij(); // error: Odd does not constrain a type
>>>>
>>>
>>> Yes, fair enough; this does conform to the grammar.
>>> --
>>> Std-Proposals mailing list
>>> Std-Proposals_at_[hidden]
>>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>>
>>
>>
>> --
>> Regards,
>> Oleksandr Koval.
>>
One more syntax proposal that extends P1985's unkiversal template parameter: `template auto`
1. allow `template auto` in any deduced context, for example `vector<template auto> vec = get_vec();`
2. use the syntax `template<class T> auto` to introduce the name `T`.
template<class T> auto x = foo()
vector<template<class V> auto> v = get_vec()
Some extra stuff:
* Introducing a name is optional, you can use `template<class> auto` for a type placeholder, instead of a universal one
* you can have nttp or template placeholders too
std::array<string, template<size_t arr_size> auto> arr = get_arr();
A bit verbose compared to my previously proposed auto<class T>. Honestly, I like that more, but I could live with this.
I definitely wouldn't want a syntax where you are required to immediately repeat the introduced name.
Cheers,
Lénárd
On 30 September 2022 15:01:58 BST, Edward Catmur via Std-Proposals <std-proposals_at_[hidden]> wrote:
>On Fri, 30 Sept 2022 at 14:19, Oleksandr Koval <
>oleksandr.koval.dev_at_[hidden]> wrote:
>
>> Sorry if this was already discussed, I like `auto<class T>` syntax but the
>> problem I see is this:
>>
>> std::vector<int> f();
>> auto<class T> v = f(); // should T be `std::vector<int>` or just `int`?
>>
>
>That syntax would work as a 2-step process: first you declare entities,
>then deduce them. The declaration and deduction should be pretty much the
>same as for (non-terse) function templates.
>
>So T is repeated:
>
>auto<class T> T v = f();
>
>or
>
>auto<class T> std::vector<T> v = f();
>
>or
>
>auto<template<class> class TT, class T> TT<T> v = f();
>
>
>It’s a bit confusing when you see them side by side. Because of that I
>> don’t think that using angle brackets is a good idea (at least I can’t find
>> any form which is not confusing). We need a new syntax which will clearly
>> show that typename(s) is closely related to `auto` itself. For example:
>>
>> auto:[class T] v = f();
>> auto:[class T1, classT2] [key, value] = get_pair();
>>
>> On Fri, Sep 30, 2022 at 4:07 AM Edward Catmur via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>>>
>>>
>>> On Thu, 29 Sept 2022 at 21:44, Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
>>> wrote:
>>>
>>>> On Thu, Sep 29, 2022 at 3:57 PM Lénárd Szolnoki via Std-Proposals <
>>>> std-proposals_at_[hidden]> wrote:
>>>>
>>>>> On 29 September 2022 20:25:06 BST, Edward Catmur <
>>>>> ecatmur_at_[hidden]> wrote:
>>>>> >On Thu, 29 Sept 2022 at 18:15, Lénárd Szolnoki via Std-Proposals <
>>>>> std-proposals_at_[hidden]> wrote:
>>>>> >
>>>>> >> I think this could be addressed by two distinct proposals.
>>>>> >>
>>>>> >> 1. allow placeholders to appear in any deduced context
>>>>> (std::vector<auto>)
>>>>> >> 2. allow a placeholder to introduce a name (auto<class T>, auto<int
>>>>> i>
>>>>> >> might appear as a deduced nttp)
>>>>> >>
>>>>> >> Then you can have your vector<auto<class T>> to deduce the value
>>>>> type and
>>>>> >> introduce the name T for that.
>>>>> >
>>>>> >std::vector<auto> is problematic, because elsewhere auto means a value
>>>>> of
>>>>> >unconstrained type (e.g. in template<auto>).
>>>>>
>>>>> I disagree. auto is a placeholder for the type of the non-type
>>>>> parameter. If you don't omit the name, then that name refers to the value.
>>>>>
>>>>
>>>> FWIW, I tend to agree with Lénárd here: `auto *p, std::unique_ptr<auto>
>>>> q` seems quite reasonable to me.
>>>>
>>>
>>> Ye-esss; looking at the grammar; `auto` is always a
>>> placeholder-type-specifier, which is a simple-type-specifier, so it makes
>>> sense that it takes the place of a concrete (or inferred) type.
>>>
>>> So Lénárd, I apologise; you're correct that in these contexts `auto`
>>> designates a type, not a value. I'm still trying to get my head round
>>> "template<auto> int f();", but the syntax is clear.
>>>
>>> *However*, I foresee practical problems with allowing auto *anywhere* in
>>>> a declaration. Consider
>>>> template<class T> void f(T t); // since C++98
>>>> template<class T> void g(decltype(T(1)) t); // since C++11
>>>> void f(auto t); // since C++20, equivalent to f #1
>>>> void g(decltype(auto(1)) t); // since C++23, *not* equivalent to g
>>>> #1
>>>>
>>>> Now, the `T` parameter to `g` is not deducible, so "obviously" the
>>>> `auto` in g #2 doesn't mean the same thing as the `auto` in f #2. But are
>>>> you sure we can teach that to the computer?
>>>>
>>>> (Background: I teach that `auto` since C++14 has (like most C++
>>>> keywords) had two meanings: concrete type *inference*, as in auto x =
>>>> 1, and templatey type *deduction*, as in [](auto x){}. The physical
>>>> mechanisms behind, and consequences of, these two usages of `auto` are
>>>> vastly different, although their human-level meaning is similar: "I don't
>>>> want to bother with types; compiler, please figure it out." So if you see
>>>> me talking about "inference" versus "deduction," or "the first meaning of
>>>> auto" versus "the second meaning of auto," that's what I'm talking about.)
>>>>
>>>
>>> The deduction process is ultimately the same; both end up in
>>> temp.deduct.call. In an abbreviated function template or generic lambda,
>>> the deduction can be overridden by explicit template argument, but that's a
>>> relatively minor effect. And syntactically, they're the same; a
>>> decl-specifier of a decl-specifier-seq (of a function parameter or variable
>>> declaration); `auto` in a function return type or trailing return type has
>>> less in common, though I'd suppose you'd class that as inference. Still, I
>>> guess it's OK to teach it that way.
>>>
>>> It would certainly *not* be reasonable to have a rule like "Try to
>>>> interpret every `auto` as deduction, but if that would result in a
>>>> non-deducible template parameter, then backtrack and assume it's inference
>>>> instead." It would be reasonable to have a rule that boils down to "Inside
>>>> the operand of a decltype or sizeof or array bound, the `auto` always means
>>>> inference not deduction." But is `g` above the *only* problem case?
>>>> Are there other corner cases where `auto` is already legal today, and/or we
>>>> wouldn't want it to mean a template parameter?
>>>> void f(A<auto(int())>); // is this concrete A<0> or templatey
>>>> A<T(int())>? I guess the type of A will disambiguate...
>>>>
>>>
>>> Currently a placeholder can appear as the decl-specifier of a function
>>> parameter, variable declaration, or template parameter or, as exactly one
>>> simple-type-specifier of a return or trailing return type,
>>> conversion function id, new expression's type id, or (`auto` only) as the
>>> type specifier of a functional cast. If these were relaxed, I think we'd
>>> probably be OK; you just go through inventing extra type template
>>> parameters and perform deduction as usual.
>>>
>>> Also I don't think ambiguity *can* be an issue, or it would be already;
>>> there must be disambiguators in the syntax. Indeed, I have a strong
>>> suspicion that your `A<auto(int())>` is a most vexing parse.
>>>
>>> Also consider that while
>>>> void h1(std::vector<auto, auto> v);
>>>> would work fine with Lénárd's proposed syntax,
>>>> void h2(std::array<auto, ??> a);
>>>> would not. That does seem mildly problematic. However, maybe it's
>>>> consistent with C++20, which permits
>>>> template<class T> concept Integral = true;
>>>> template<Integral T> void ij(); // since C++20
>>>> but not
>>>> template<int N> concept Odd = true;
>>>> template<Odd N> void ij(); // error: Odd does not constrain a type
>>>>
>>>
>>> Yes, fair enough; this does conform to the grammar.
>>> --
>>> Std-Proposals mailing list
>>> Std-Proposals_at_[hidden]
>>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>>
>>
>>
>> --
>> Regards,
>> Oleksandr Koval.
>>
Received on 2022-09-30 16:38:42