how to write this function in C++ using meta programming

What are you trying to achieve

I want to convert RetType ClassA::MemberFunc(Args...) to mem_fn(&ClassA::MemberFunc) but it is like a function in order to avoid write lambda or function for every member functions

What did you get out (include error messages)

no matching function for call to ‘regisAdd(std::_Mem_fn<int (ABC::*)(int, int)>)’

Here is my code.

#include <functional>
#include <iostream>

using namespace std;

struct ABC {
    int value;
    int add(int a, int b) {
        return a + b * value;
    }
    int other(int a) {
        return a * value;
    }
};

int doAdd(void* data, int a, int b) {
    ABC* p = (ABC*)data;
    return p->add(a, b);
}

typedef int (*TYPE_ADD)(void* data, int a, int b);
TYPE_ADD gAdd = nullptr;
void regisAdd(TYPE_ADD a) {
    gAdd = a;
}

void callAdd() {
    if (!gAdd) return;
    ABC abc;
    abc.value = 10;
    cout << gAdd(&abc, 1, 2) << endl;
}

typedef int (*TYPE_OTHER)(void* data, int a);
TYPE_OTHER gOther = nullptr;
void regisOther(TYPE_OTHER a) {
    gOther = a;
}
void callOther() {
    if (!gOther) return;
    ABC abc;
    abc.value = 10;
    cout << gOther(&abc, 12) << endl;
}

int main() {
    regisAdd(doAdd);                               // this is GOOD
    callAdd();                                     // call
    regisAdd([](void* data, int a, int b) {        // < this is also GOOD
        return static_cast<ABC*>(data)->add(a, b); // < GOOD
    });                                            // < GOOD
    callAdd();                                     // call

    // how to write a general function work like mem_fn
    // to avoid write doAdd and lambda for every function signatures
    // regisAdd(mem_fn(&ABC::add));
    // regisOther(mem_fn(&ABC::other));
    // callAdd();
    return 0;
}

Solution 1:

As I understand, you want something like:

template <auto mem> // C++17, else <typename T, T mem>
struct mem_to_func;

template <typename C, typename Ret, typename ... Args,
          Ret (C::*m)(Args...)>
struct mem_to_func<m>
{
    static Ret func_ptr(C* c, Args... args)
    {
        return (c->*m)(std::forward<Args>(args)...);
    }
    static Ret func_ref(C& c, Args... args)
    {
        return (c.*m)(std::forward<Args>(args)...);
    }
    static Ret func_voidp(void* p, Args... args)
    {
        auto* c = static_cast<C*>(p);
        return (c->*m)(std::forward<Args>(args)...);
    }
};

template <typename C, typename Ret, typename ... Args,
          Ret (C::*m)(Args...) const>
struct mem_to_func<m>
{
    static Ret func(const C* c, Args... args)
    {
        return (c->*m)(std::forward<Args>(args)...);
    }
    static Ret func_ref(const C& c, Args... args)
    {
        return (c.*m)(std::forward<Args>(args)...);
    }
    static Ret func_voidp(const void* p, Args... args)
    {
        const auto* c = static_cast<const C*>(p);
        return (c->*m)(std::forward<Args>(args)...);
    }
};
// Others specializations for combination with
// - volatile,
// - reference to this,
// - and C-ellipsis... 

and then

regisAdd(mem_to_func<&ABC::add>::func_voidp);