类的成员函数作为函数指针

网上找了半天没找到,还是看官方文档比较清晰:std::function - cppreference.com (polytechnique.fr)

同时给出自己设计C类型的成员函数指针的形式。

其实函数指针要给函数的地址,那么地址一定要是全局的才可以。所以实现有两种思路,一种是直接再类中定义一个静态成员函数;另一种是可以用全局函数回调std::function定义的可调用对象函数。std::function的好处是可以局部使用不用全局。

#include<iostream>
#include<functional>

typedef int(*AddPtr)(int, int);

std::function<int(int, int)> 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<int(int, int)> 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 <type_traits>
#include <iostream>
#include <utility>
#include<iostream>
#include<functional>

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 <typename Callable>
union storage
{
    storage() {}
    std::decay_t<Callable> callable;
};

template <int, typename Callable, typename Ret, typename... Args>
auto fnptr_(Callable &&c, Ret (*)(Args...))
{
    static bool used = false;
    static storage<Callable> s;
    using type = decltype(s.callable);

    if (used)
        s.callable.~type();
    new (&s.callable) type(std::forward<Callable>(c));
    used = true;

    return [](Args... args) -> Ret
    {
        return Ret(s.callable(std::forward<Args>(args)...));
    };
}

template <typename Fn, int N = 0, typename Callable>
Fn *fnptr(Callable &&c)
{
    return fnptr_<N>(std::forward<Callable>(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<int(int,int)>([&fun_ptr](int x, int y){return fun_ptr(x, y);});
    // AddPtr lambda_add = fnptr<int(int,int)>(std::bind(&Cal::add, cal, std::placeholders::_1, std::placeholders::_2));
    // AddPtr lambda_add = fnptr<int(int,int)>(fun_ptr);
    // fun(5, 6, lambda_add);

    // Error :
    std::function<int(int, int)> fun_ptr = std::bind(&Cal::add, cal, std::placeholders::_1, std::placeholders::_2);
    AddPtr lambda_add = fnptr<int(int,int)>(fun_ptr);
    fun(5, 6, lambda_add);


}

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值