Are these not different types? One is a member function pointer, which requires two arguments - a Real* and an int - whereas the other is a function pointer which requires one argument - an int;

You can do the following:

template<typename C, typename F>
auto user(C &c, F func){
    if constexpr(std::is_member_function_pointer<F>::value){
        return (c.*func)(5);
    } else{
        return func(5);
    }
}

And subsequently call via:

user(real, &Real::inc);

user(real, Mock::inc);


On Mon, 25 May 2020, 1:16 pm Nikolay Mihaylov via Std-Proposals, <std-proposals@lists.isocpp.org> wrote:
Hello,

suppose you have following clases:

struct Mock{
static int inc(int){
return 0;
} static int dec(int){
return 0;
}
}; struct Real{
Real(int v) : v(v){} int inc(int a) const{
return a + v;
} int dec(int a) const{
return a - v;
} private:
int v;
}; template<typename C, typename F>
auto user(C &c, F func){
return (c.*func)(5);
}
This will allow to call:

user(real, &Real::inc);

but will not allow to do

user(real, &Mock::inc);

However because of generic context, both calls must be possible.

Here is simple implementation of the feature:

#include <type_traits>

namespace class_invoke_impl_{
    template <class T, class F, class... Args>
    constexpr auto class_invoke_(T &&cl, F func, std::true_type, Args&&... args){
        return (std::forward<T>(cl).*func)(std::forward<Args>(args)...);
    } 
 
    template <class T, class F, class... Args>
    constexpr auto class_invoke_(T const &, F func, std::false_type, Args&&... args){
        return func(std::forward<Args>(args)...);
    }
 
template <class T, class F, class... Args>
constexpr auto class_invoke(T &&cl, F func, Args&&... args){
    using namespace class_invoke_impl_;
    return class_invoke_(std::forward<T>(cl), func, std::is_member_pointer<F>{}, std::forward<Args>(args)...);
}


 
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals