On Tue, Nov 29, 2022 at 7:09 AM Frederick Virchanza Gotham via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On Tue, Nov 29, 2022 at 10:29 AM Frederick Virchanza Gotham <cauldwell.thomas@gmail.com> wrote:
>
> template<text K, typename T>
> constexpr auto GetRelevantMethodPointer(T const *const p)
> {
>          if constexpr (    false == std::is_class_v<T>    ) return
> static_cast<void(*)(void)>(nullptr);
>     else if constexpr ( std::derived_from<T,std::istream> ) return &T::read;
>     else if constexpr (        requires { &T::put; }      ) return &T::put;
>     else
>     {
>         return &T::K;
>     }
> }

This wasn't a very good example. A better example would be where we
want to find a member of the same name in a different class. See line
#7 in the following:

00:   template<typename T>
01:   constexpr auto GetRelevantMethodPointer(T const *const p)
02:   {
03:           if constexpr ( false == std::is_class_v<T> ) return
04:   static_cast<void(*)(void)>(nullptr);
05:      else if constexpr ( std::derived_from<T,std::istream> )
return &T::read;
06:      else if constexpr ( requires { &T::put; } ) return &T::put;
07:      else if constexpr ( requires { &SomeOtherClass::K; } ) return
&SomeOtherClass::K;
08:      else
09:      {
10:          return &T::K;
11:      }
12:   }

This doesn't seem like idiomatic C++ code at all. Generally in C++ you need to stay far away from pointers-to-member, because member functions can be overloaded, or can be function templates, at which point it's impossible to get a member pointer to them at all. Prefer to use C++11 lambdas instead.

template<class T, class Fallback>
auto GetReaderFunction(const T *p, Fallback fallback) {
    static_assert(std::is_class_v<T>);
    if constexpr (std::derived_from<T, std::istream>) {
        return [p](char *s, size_t n) { p->read(s, n); };
    } else if constexpr (requires (char *s, size_t n) { p->put(s, n); }) {
        return [p](char *s, size_t n) { p->put(s, n); };
    } else {
        return fallback;
    }
}

struct Foo {
    void put(auto*, size_t) {}
};
struct Bar {
    void baz(size_t) {}
};

int main() {
    Foo foo;
    Bar bar;
    auto one = GetReaderFunction(&std::cin, 0);
    auto two = GetReaderFunction(&foo, 0);
    auto three = GetReaderFunction(&bar, [&bar](char*, size_t n) { bar.baz(n); });
}

Looking at the call-sites in `main`, you quickly realize that there's no reason to ever pass `fallback` — it will be known statically at compile time whether that parameter is meaningful or not, and if it is meaningful then there's literally no reason to call `GetReaderFunction` in the first place. So this code can continue to be simplified beyond what I've done here.

–Arthur