Date: Sun, 20 Nov 2022 20:28:38 +0000
Hi,
On 20 November 2022 16:59:16 GMT, Arthur O'Dwyer via Std-Proposals <std-proposals_at_[hidden]> wrote:
>On Sun, Nov 20, 2022 at 10:25 AM Jason McKesson via Std-Proposals <
>std-proposals_at_[hidden]> wrote:
>
>> On Sun, Nov 20, 2022 at 9:51 AM Kilian Henneberger wrote:
>> >
>> > I want to raise the idea of also allowing conversion functions to be
>> static.
>> >
>> > template<auto X>
>> > struct ConvertsTo {
>> > static operator auto() { return X; }
>> > };
>> >
>> > I don't know, if code like this actually exists today and would benefit
>> from my proposed change.
>>
>> [...] it'd be better if you used a concrete type from the standard library
>> [...]
>> `integral_constant` (and its ilk).
>
>
>+1.
>
>
>> Lastly, on a completely unrelated note, has anyone suggested a
>> "statically_invocable<T, R, Args>" concept, which is true if `T` can
>> be default initialized, is not a function/member pointer, and it has a
>> static `operator()` that can be called with the given arguments? It
>> would be possible to update `std::function` and its ilk to recognize
>> such types and not bother to even store them
>
>
>That sounds useful, and IIUC could be implemented in userspace simply like
>this:
> template<class T, class... Args>
> concept StaticallyInvocable = requires (T t, Args&&... args) {
> t(std::forward<Args>(args)...);
> T::operator()(std::forward<Args>(args)...);
> };
>At first I thought this would misbehave for types where the static and
>non-static operators do different things, like
> struct S1 {
> int operator()(const std::string& s) const { return 1; }
> static int operator()(std::string_view sv) { return 2; }
> };
>or
> struct S2 {
> using F = int(*)(const std::string&);
> operator F() const { return [](const std::string&){ return 1; }; }
> static int operator()(std::string_view sv) { return 2; }
> };
>but happily Godbolt tells me that those are both ambiguous —
>`T::operator()(s)` will still do overload resolution among *all* the
>`operator()`s, and then, if the best-matching one turns out to be
>non-callable (e.g. because it is non-static and you failed to provide an
>object to operate on), it'll just hard-error. This is similar to how
>overload resolution works for constructors (if the best-matching
>constructor for an implicit conversion turns out to be `explicit`).
This is only true for copy list init. For regular copy init the explicit constructors are not included in the overload set.
>I'm not versed enough in "Deducing `this`" to know whether that will add
>any insurmountable wrinkles.
>
>That is, the puzzle challenge here is to find a type `T` such that both
>`t(args...)` and `T::operator()(args...)` are well-formed, but do different
>things at runtime. If you find such a `T`, please let me know!
>
>–Arthur
Cheers,
Lénárd
On 20 November 2022 16:59:16 GMT, Arthur O'Dwyer via Std-Proposals <std-proposals_at_[hidden]> wrote:
>On Sun, Nov 20, 2022 at 10:25 AM Jason McKesson via Std-Proposals <
>std-proposals_at_[hidden]> wrote:
>
>> On Sun, Nov 20, 2022 at 9:51 AM Kilian Henneberger wrote:
>> >
>> > I want to raise the idea of also allowing conversion functions to be
>> static.
>> >
>> > template<auto X>
>> > struct ConvertsTo {
>> > static operator auto() { return X; }
>> > };
>> >
>> > I don't know, if code like this actually exists today and would benefit
>> from my proposed change.
>>
>> [...] it'd be better if you used a concrete type from the standard library
>> [...]
>> `integral_constant` (and its ilk).
>
>
>+1.
>
>
>> Lastly, on a completely unrelated note, has anyone suggested a
>> "statically_invocable<T, R, Args>" concept, which is true if `T` can
>> be default initialized, is not a function/member pointer, and it has a
>> static `operator()` that can be called with the given arguments? It
>> would be possible to update `std::function` and its ilk to recognize
>> such types and not bother to even store them
>
>
>That sounds useful, and IIUC could be implemented in userspace simply like
>this:
> template<class T, class... Args>
> concept StaticallyInvocable = requires (T t, Args&&... args) {
> t(std::forward<Args>(args)...);
> T::operator()(std::forward<Args>(args)...);
> };
>At first I thought this would misbehave for types where the static and
>non-static operators do different things, like
> struct S1 {
> int operator()(const std::string& s) const { return 1; }
> static int operator()(std::string_view sv) { return 2; }
> };
>or
> struct S2 {
> using F = int(*)(const std::string&);
> operator F() const { return [](const std::string&){ return 1; }; }
> static int operator()(std::string_view sv) { return 2; }
> };
>but happily Godbolt tells me that those are both ambiguous —
>`T::operator()(s)` will still do overload resolution among *all* the
>`operator()`s, and then, if the best-matching one turns out to be
>non-callable (e.g. because it is non-static and you failed to provide an
>object to operate on), it'll just hard-error. This is similar to how
>overload resolution works for constructors (if the best-matching
>constructor for an implicit conversion turns out to be `explicit`).
This is only true for copy list init. For regular copy init the explicit constructors are not included in the overload set.
>I'm not versed enough in "Deducing `this`" to know whether that will add
>any insurmountable wrinkles.
>
>That is, the puzzle challenge here is to find a type `T` such that both
>`t(args...)` and `T::operator()(args...)` are well-formed, but do different
>things at runtime. If you find such a `T`, please let me know!
>
>–Arthur
Cheers,
Lénárd
Received on 2022-11-20 20:28:42