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);