网上找了半天没找到,还是看官方文档比较清晰:std::function - cppreference.com (polytechnique.fr)
同时给出自己设计C类型的成员函数指针的形式。
其实函数指针要给函数的地址,那么地址一定要是全局的才可以。所以实现有两种思路,一种是直接再类中定义一个静态成员函数;另一种是可以用全局函数回调std::function定义的可调用对象函数。std::function的好处是可以局部使用不用全局。
#include
#include
typedef int(*AddPtr)(int, int);
std::function add_callback;
class Cal
{
public:
static int s_add(int x, int y)
{
std::cout << "static fun : \n";
return x + y;
}
int add(int x, int y)
{
return x + y;
}
};
void fun(int a, int b, std::function ptr)
{
std::cout << "use function :\n";
int res = ptr(a, b);
std::cout << "a + b = " << res << "\n";
}
void fun(int a, int b, AddPtr ptr)
{
std::cout << "no use function :\n";
int res = ptr(a, b);
std::cout << "a + b = " << res << "\n";
}
// 全局函数形式
int g_add(int x, int y)
{
return add_callback(x, y);
}
int main()
{
Cal cal;
add_callback = std::bind(&Cal::add, cal, std::placeholders::_1, std::placeholders::_2);
fun(5, 7, add_callback);
AddPtr ptr = g_add;
fun(5, 7, ptr);
AddPtr ptr2 = &Cal::s_add;
fun(5, 7, ptr2);
}
如果有多个类的成员函数都想使用函数指针的形式调用,每个成员函数都要写一个全局的函数非常的麻烦,所以可以使用模板让编译器来生成的代码,这样写一份等于无数份。具体示例如下:
#include
#include
#include
#include
#include
typedef int(*AddPtr)(int, int);
class Cal
{
public:
int add(int x, int y)
{
return x + y;
}
};
void fun(int a, int b, AddPtr ptr)
{
std::cout << "no use function :\n";
int res = ptr(a, b);
std::cout << "a + b = " << res << "\n";
}
template
union storage
{
storage() {}
std::decay_t callable;
};
template
auto fnptr_(Callable &&c, Ret (*)(Args...))
{
static bool used = false;
static storage s;
using type = decltype(s.callable);
if (used)
s.callable.~type();
new (&s.callable) type(std::forward(c));
used = true;
return [](Args... args) -> Ret
{
return Ret(s.callable(std::forward(args)...));
};
}
template
Fn *fnptr(Callable &&c)
{
return fnptr_(std::forward(c), (Fn *)nullptr);
}
int main()
{
Cal cal;
// Right :
// auto fun_ptr = std::bind(&Cal::add, cal, std::placeholders::_1, std::placeholders::_2);
// AddPtr lambda_add = fnptr([&fun_ptr](int x, int y){return fun_ptr(x, y);});
// AddPtr lambda_add = fnptr(std::bind(&Cal::add, cal, std::placeholders::_1, std::placeholders::_2));
// AddPtr lambda_add = fnptr(fun_ptr);
// fun(5, 6, lambda_add);
// Error :
std::function fun_ptr = std::bind(&Cal::add, cal, std::placeholders::_1, std::placeholders::_2);
AddPtr lambda_add = fnptr(fun_ptr);
fun(5, 6, lambda_add);
}