C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Named auto

From: Lénárd Szolnoki <cpp_at_[hidden]>
Date: Thu, 29 Sep 2022 20:42:13 +0100
Hi,

I don't like auto<class T> vector<T> because T needs to be present twice. It ceases to be concise once you steer away from one-letter names.

Also what if you don't actually care about T here, but you want the overload to only match vectors? Then you can't use this syntax without needlessly introducing a name.

I'm not married to the particular syntax I suggested to the two separate proposals, but I think if still has merit two handle the two cases separately.


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 don't agree with this. Here auto is a placeholder for the type of the non-type template parameter. It's not the auto that means value of unconstrained type. That is the name that you omitted.

>
>That's why I'd prefer auto<class T> vector<T>; also because it's
>syntactically regular (as soon as you hit `auto<` you know what's going on).
>
>Cheers,
>> Lénárd
>>
>> On 29 September 2022 17:57:27 BST, Keenan Horrigan via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>>
>>> > By pattern matching, I mean deducing `T` from `std::vector<T>`, or `U`
>>> and `N` from `std::array<U, N>`, or `R` and `A` from `R(*)(A...)`, etc.
>>>
>>> Ah I see, yes the 'T{auto}' syntax doesn't do that, and I think that's
>>> okay, because if it were to do that it would lose how terse it is.
>>>
>>> > But you can't use explicit function template syntax to initialize a
>>> local variable in block scope.
>>>
>>> Yes, to be clear I'm not advocating against your suggestions, I think
>>> they are decent and that some form of what you're suggesting is useful and
>>> should be added to the language. I'm just advocating for some form of terse
>>> syntax to name what 'auto' would otherwise name, for the primary purpose of
>>> function parameters. I'm not in any way trying to say that such a terse
>>> syntax would solve the entire scope of the problem, because it doesn't, but
>>> that doesn't mean that it shouldn't be added.
>>>
>>> > That is, deducing the typename `char_t` into scope but without it being
>>> a template parameter per se.
>>>
>>> Ahh, that makes sense.
>>> ------- Original Message -------
>>> On Thursday, September 29th, 2022 at 11:32 AM, Edward Catmur <
>>> ecatmur_at_[hidden]> wrote:
>>>
>>>
>>>
>>> On Thu, 29 Sept 2022 at 15:56, Keenan Horrigan <
>>> friedkeenan_at_[hidden]> wrote:
>>>
>>>> > The issues I have with that syntax are:
>>>> > * looks like it would be difficult/ambiguous to parse/lex (by
>>>> compilers, editors, etc.)
>>>> > * excessively terse - nowhere else do we introduce a type name into
>>>> scope without a keyword preceding it
>>>> > * can't pattern match, deduce non-types or more than one type
>>>> >
>>>> > For that last point, it means that that syntax would not be a complete
>>>> replacement for explicit function template syntax, nor for decltype (+
>>>> worse!) at block scope, so we'd have yet more syntax to teach. I don't
>>>> think much of the claim that C++ is overly complex, but I do feel that
>>>> additions should try to simplify the "modern" subset of the language, i.e.
>>>> those parts that are sufficient to write new code.
>>>>
>>>> The ambiguity of syntax is a concern I had too, would require more
>>>> investigation to determine if it's really an issue, though that effort
>>>> should not be spent before determining if it would be a good syntax in the
>>>> first place.
>>>>
>>>> I can see how one might think it's excessively terse, I think I'd
>>>> disagree though. Yes, type names have never before been introduced without
>>>> some sort of declarative keyword (well, besides god-given types like int),
>>>> but that requirement of a keyword is part of what makes the currently
>>>> available options not terse enough in my opinion.
>>>>
>>>> If I understand correctly what you mean by pattern matching, I think the
>>>> 'T{auto}' syntax can do that, since 'T' would just be naming what 'auto'
>>>> otherwise would take the place of, so you could do 'const T{auto} &var =
>>>> 1;' and the 'T' would name 'int'.
>>>>
>>>
>>> By pattern matching, I mean deducing `T` from `std::vector<T>`, or `U`
>>> and `N` from `std::array<U, N>`, or `R` and `A` from `R(*)(A...)`, etc.
>>>
>>> You're correct on the other things though, that it can't deduce non-types
>>>> or multiple types, but I'm not sure a terse syntax needs to, since anything
>>>> more than just putting a name to 'auto' would require syntax that is not
>>>> terse enough I feel, and so if you need more complexity you would use the
>>>> explicit function template syntax, which is how the current situation with
>>>> abbreviated function template syntax works.
>>>>
>>>
>>> But you can't use explicit function template syntax to initialize a local
>>> variable in block scope.
>>>
>>> Thank you for the examples by the way, I think perhaps they could be
>>>> better abstracted in these instances but they do demonstrate a want for
>>>> block scope named deduction (though I'm not sure the last one falls under
>>>> that since it's just sorta normal use of decltype).
>>>>
>>>
>>> For the last one I would hope to be able to write:
>>>
>>> template <auto<typename char_t, size_t N>
>>> detail_exported::fixed_string<char_t, N> Str> constexpr auto
>>> operator""_cf() {
>>>
>>> That is, deducing the typename `char_t` into scope but without it being a
>>> template parameter per se.
>>>
>>> I do think the 'T{auto}' syntax could address all the examples you gave,
>>>> it might have issues when used with just plain 'auto' and maybe that 'auto'
>>>> would deduce a 'const' or something which could cause issues with
>>>> 'is_same', but I'm not sure the other syntax suggestions would handle that
>>>> either.
>>>>
>>>
>>> That's good reason to use `const` alongside `auto` - and Victor does
>>> that, to his credit. So that should work fine.
>>>
>>> Where I expect frustration to arise is when you realize that you actually
>>> wanted to pattern match on the type of the initializer.
>>>
>>> ------- Original Message -------
>>>> On Thursday, September 29th, 2022 at 6:46 AM, Edward Catmur <
>>>> ecatmur_at_[hidden]> wrote:
>>>>
>>>> On Wed, 28 Sept 2022 at 19:33, Keenan Horrigan <
>>>> friedkeenan_at_[hidden]> wrote:
>>>>
>>>>> > Yes, it's fairly common, and getting more so as previously
>>>>> callback-style code (that could use lambda explicit template syntax) moves
>>>>> to coroutines. It's frustrating when a nicely deduced, constrained and/or
>>>>> pattern matched parameter becomes a coroutine local variable that now can
>>>>> only be matched using the meagre `auto` syntax.
>>>>>
>>>>> Would love to see an example just for my own curiosity, but I'll take
>>>>> your word for it anyhow.
>>>>>
>>>>
>>>> Here's a couple of examples in just one file:
>>>>
>>>>
>>>> https://github.com/fmtlib/fmt/blob/0ccaed3a6c745ed2a625b8d6531111ba668e4fea/include/fmt/compile.h#L206-L207
>>>>
>>>> https://github.com/fmtlib/fmt/blob/0ccaed3a6c745ed2a625b8d6531111ba668e4fea/include/fmt/compile.h#L317-L318
>>>>
>>>> https://github.com/fmtlib/fmt/blob/0ccaed3a6c745ed2a625b8d6531111ba668e4fea/include/fmt/compile.h#L541-L542
>>>>
>>>> https://github.com/fmtlib/fmt/blob/0ccaed3a6c745ed2a625b8d6531111ba668e4fea/include/fmt/compile.h#L600-L601
>>>>
>>>> I think your 'using { ... }' syntax would be fine for named deduction
>>>>> for normal variable declarations, though I wouldn't mind e.g. 'auto<class
>>>>> T>' either, though I think the 'using' version is better and more clear. I
>>>>> feel though that that would only solve one aspect of this problem, and not
>>>>> the aspect of deduced function parameter types. Really I just want
>>>>> something that would give me the type that 'auto' would otherwise name in
>>>>> the abbreviated function template syntax, so for me something like
>>>>>
>>>>> void named_auto(T{auto} &&to_be_forwarded);
>>>>>
>>>>> is perfectly acceptable to me. Maybe these separate aspects of this
>>>>> problem should be given separate solutions? That runs the risk of having
>>>>> more than one good way to do named deduction, at least for deduced types,
>>>>> but I feel that may be a fine enough situation.
>>>>>
>>>>
>>>> The issues I have with that syntax are:
>>>> * looks like it would be difficult/ambiguous to parse/lex (by compilers,
>>>> editors, etc.)
>>>> * excessively terse - nowhere else do we introduce a type name into
>>>> scope without a keyword preceding it
>>>> * can't pattern match, deduce non-types or more than one type
>>>>
>>>> For that last point, it means that that syntax would not be a complete
>>>> replacement for explicit function template syntax, nor for decltype (+
>>>> worse!) at block scope, so we'd have yet more syntax to teach. I don't
>>>> think much of the claim that C++ is overly complex, but I do feel that
>>>> additions should try to simplify the "modern" subset of the language, i.e.
>>>> those parts that are sufficient to write new code.
>>>>
>>>> ------- Original Message -------
>>>>> On Wednesday, September 28th, 2022 at 12:48 PM, Edward Catmur <
>>>>> ecatmur_at_[hidden]> wrote:
>>>>>
>>>>>
>>>>>
>>>>> On Wed, 28 Sept 2022 at 17:56, Keenan Horrigan <
>>>>> friedkeenan_at_[hidden]> wrote:
>>>>>
>>>>>> > We already have syntax for function template parameter named
>>>>>> deduction; we don't need another. What we don't have is a syntax for block
>>>>>> scope named deduction.
>>>>>>
>>>>>> Well, we also currently have ways to get the types deduced through
>>>>>> your syntax suggestions, they're just suboptimal (using decltype,
>>>>>> remove_cvref etc.).
>>>>>>
>>>>>
>>>>> Pattern matching the type is very much suboptimal as well; it requires
>>>>> creating helper metaclasses, alias templates etc., or abusing lambdas.
>>>>>
>>>>>> Similarly, I find the current state of named function parameter
>>>>>> deduction suboptimal. We have the normal 'template<...>' syntax, and then
>>>>>> we have the terse syntax with auto-parameters. Right now I steer away from
>>>>>> the terse syntax because when I deduce a type for a function parameter, I
>>>>>> very often want to also name that deduced type, so I might as well use the
>>>>>> 'template<...>' syntax. However, the terse syntax is more concise, and I
>>>>>> would argue more readable were it not for the fact that it necessitates
>>>>>> some use of decltype to name the type, and similarly may require
>>>>>> remove_cvref etc. to be applied. I find this suboptimal, and would very
>>>>>> much enjoy being able to use the terse syntax and some form of "named auto".
>>>>>>
>>>>>
>>>>> There's no reason that `auto<class T> T x` couldn't be accepted in
>>>>> function template parameter position as well; it just feels redundant.
>>>>>
>>>>> Also there's the issue that when supplying function template argument
>>>>> explicitly (as f<A...>(a...)) to a terse function template it's not
>>>>> entirely obvious which template argument corresponds to which argument. But
>>>>> then again, named deduction wouldn't exactly worsen this issue.
>>>>>
>>>>> Truthfully as well, I cannot recall a time where I've wanted to name a
>>>>>> deduced type of a variable that wasn't a function parameter. Is this a
>>>>>> common occurrence for others? It of course would be better to have syntax
>>>>>> that allows for it, but I personally don't find a solution that doesn't
>>>>>> allow named deduction with the abbreviated function template syntax
>>>>>> appealing.
>>>>>>
>>>>>
>>>>> Yes, it's fairly common, and getting more so as previously
>>>>> callback-style code (that could use lambda explicit template syntax) moves
>>>>> to coroutines. It's frustrating when a nicely deduced, constrained and/or
>>>>> pattern matched parameter becomes a coroutine local variable that now can
>>>>> only be matched using the meagre `auto` syntax.
>>>>>
>>>>> ------- Original Message -------
>>>>>> On Wednesday, September 28th, 2022 at 10:39 AM, Edward Catmur <
>>>>>> ecatmur_at_[hidden]> wrote:
>>>>>>
>>>>>> On Wed, 28 Sept 2022 at 16:24, Keenan Horrigan <
>>>>>> friedkeenan_at_[hidden]> wrote:
>>>>>>
>>>>>>> My issue with the 'using' syntax was that it seems redundant when
>>>>>>> used with function parameter type deduction (because why wouldn't you just
>>>>>>> type out the normal 'template<...>'), I don't see how your 'auto<class T> T
>>>>>>> var' syntax addresses that beyond maybe putting the deduced entities closer
>>>>>>> to their source? Not a hugely compelling reason to use it over normal
>>>>>>> template parameters in my opinion.
>>>>>>>
>>>>>>
>>>>>> We already have syntax for function template parameter named
>>>>>> deduction; we don't need another. What we don't have is a syntax for block
>>>>>> scope named deduction.
>>>>>>
>>>>>>> ------- Original Message -------
>>>>>>> On Wednesday, September 28th, 2022 at 10:08 AM, Edward Catmur via
>>>>>>> Std-Proposals <std-proposals_at_[hidden]> wrote:
>>>>>>>
>>>>>>> On Wed, 28 Sept 2022 at 15:14, Jason McKesson via Std-Proposals <
>>>>>>> std-proposals_at_[hidden]> wrote:
>>>>>>>
>>>>>>>> On Wed, Sep 28, 2022 at 10:06 AM Sébastien Bini via Std-Proposals
>>>>>>>> <std-proposals_at_[hidden]> wrote:
>>>>>>>> >
>>>>>>>> > How about a syntax similar to that of parameters then?
>>>>>>>> >
>>>>>>>> > template <class T> T var = foo();
>>>>>>>> > template <class K, class V> std::pair<K const, V>& kv =
>>>>>>>> *map.begin(); // or [k, v]?
>>>>>>>> > template <std::copyable T, auto I> std::array<T, I> arr = getArr();
>>>>>>>> > template <std::size_t... I> [[maybe_unused]]
>>>>>>>> std::index_sequence<I...> seq = std::index_sequence_for<Args...>();
>>>>>>>> >
>>>>>>>> > Then we don't need to reinvent the syntax for parameters.
>>>>>>>>
>>>>>>>
>>>>>>> That syntax is already in use for variable templates. Maybe named
>>>>>>> deduction is at block scope and variable templates are at namespace scope,
>>>>>>> but that kind of overloading of meaning is pretty horrible - `static` is
>>>>>>> bad enough.
>>>>>>>
>>>>>>> Let's re-examine the problem that people seem to want to solve.
>>>>>>>>
>>>>>>>> My understanding was that the principal problem was that you want to
>>>>>>>> gain access to the actual typename that the placeholder deduction
>>>>>>>> syntax yields, and sticking a `using name = decltype(var_name);` is
>>>>>>>> both wordy and error-prone (I deliberately did that wrong, for
>>>>>>>> example).
>>>>>>>>
>>>>>>>> The main reason people deduce types is because they don't want to
>>>>>>>> have
>>>>>>>> to type out the full name of the type
>>>>>>>
>>>>>>>
>>>>>>> or because the type is unnameable, or because it's dependent, or
>>>>>>> because the code you're calling could change its return type and so typing
>>>>>>> it out is a hostage to fortune.
>>>>>>>
>>>>>>>> (or because it's already
>>>>>>>> mentioned in the initializing expression).
>>>>>>>
>>>>>>>
>>>>>>> If you're using AAA with types on the RHS then you don't need to
>>>>>>> deduce them again, so you wouldn't need named deduction.
>>>>>>>
>>>>>>>> So it seems to me that
>>>>>>>> injecting a bunch more words into such a declaration is...
>>>>>>>> counter-productive.
>>>>>>>>
>>>>>>>> Yes, any of these declarations might be useful. But... are they
>>>>>>>> really
>>>>>>>> *that* useful? So useful that we want to type out (and read) all of
>>>>>>>> that?
>>>>>>>>
>>>>>>>
>>>>>>> We are proposing that a single statement introduce not just
>>>>>>> potentially multiple entity names, but also potentially multiple type
>>>>>>> aliases (also, maybe, packs, templates, concepts). This is a novel
>>>>>>> challenge for compilers and other tools, and it needs *some* introducing
>>>>>>> syntax to shunt the parser down the new code paths; lexing is difficult
>>>>>>> enough as it is.
>>>>>>>
>>>>>>> If `using` is too much typing, how about the introducer being `auto
>>>>>>> <`? It seems that the lexer should be able to detect that pretty much
>>>>>>> immediately.
>>>>>>>
>>>>>>> auto<class T> T var = foo();
>>>>>>> // etc.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>

Cheers,
Lénárd

Received on 2022-09-29 19:42:18