C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Allow static conversion function

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Sun, 20 Nov 2022 11:59:16 -0500
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`).
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

Received on 2022-11-20 16:59:29