c++通过如何判断是否为同一个函数

场景

注册回调函数,判断是否是重复注册

方法

C++中针对std::function类型数据,可以通过如下的方式判断

比如using RecvCb_t = std::function<void(const uint8_t *, size_t)>;

using RecvCb_t = std::function<void(const uint8_t *, size_t)>;

void test_func1(const uint8_t *data, size_t size) {
    std::cout<<"func1"<<std::endl;
    return;

}

void test_func2(const uint8_t *data, size_t size) {
    std::cout<<"func2"<<std::endl;
    return;

}

RecvCb_t func1 = test_func1;
RecvCb_t func2 = test_func2;

if (func1.target<void (*)(const uint8_t *, size_t)>() == func2.target<void (*)(const uint8_t *, size_t)>()) {
    std::cout<<"It's same func"<<std::cout;
}else{
    std::cout<<"It's different func"<<std::cout;
}

上面会输出"It's same func",可以正确判断是不同的两个函数

但如果

RecvCb_t func1 = std::bind(&test_func1, std::placeholders::_1, std::placeholders::_2);
RecvCb_t func2 = std::bind(&test_func2, std::placeholders::_1, std::placeholders::_2);

 就会输出"It's different func",别错误的识别为了同一个函数

原因分析

虽然 test_func1 和 test_func2 是两个不同的函数,但是当你使用 std::bind 并使用 std::placeholders 占位符之后,std::bind 返回的是一个函数对象,并且这两个函数对象的类型是相同的。

在使用了 func1.target<void (*)(const uint8_t *, size_t)>() 和 func1.target<void (*)(const uint8_t *, size_t)>() 来获取函数指针并进行比较。由于类型擦除机制,std::bind 返回的函数对象在进行 target<void (*)(const uint8_t *, size_t)>() 操作时,会得到相同的函数指针类型,导致判断错误。

解决方法

为了解决这个问题,你需要区分通过 std::bind 生成的不同函数对象。一种可行的方案是:

为每个回调函数定义一个包装类:也就是仿函数,函数对象

class TestFunc1 { 
    public: void operator()(const uint8_t * data, size_t len) { 
        test_func1(data, len); 
    } 
};
class TestFunc2 {
    public: void operator()(const uint8_t * data, size_t len) {
        test_func2(data, len);
    }
};

RecvCb_t func1 = TestFunc1();
RecvCb_t func2 = TestFunc2();

仿函数也称为函数对象是 C++ 中的一种编程概念,指的是行为类似函数的对象。本质上,仿函数是一个定义了 operator() 运算符的类,使得该类的对象可以像函数一样被调用。

仿函数的特点:

  • 像函数一样调用: 仿函数对象可以使用函数调用语法 () 进行调用。
  • 可以拥有状态: 与普通函数不同,仿函数可以拥有自己的成员变量,用于存储状态或配置信息。
  • 可以作为函数参数传递: 仿函数可以作为参数传递给其他函数,例如 STL 算法函数。
  • 类型安全: 编译器会对仿函数的参数类型进行检查,提高了代码的类型安全性。

仿函数的优点:

  • 更灵活的参数绑定: 可以使用 std::bind 等工具方便地绑定参数,生成新的仿函数。
  • 可以拥有状态: 可以保存每次调用的状态,方便实现一些有状态的算法。
  • 提高代码可读性: 通过定义语义化的仿函数,可以提高代码的可读性和可维护性。

仿函数的应用场景:

  • STL 算法库: STL 中大量使用了仿函数,例如 std::sortstd::for_each 等算法函数,可以接受仿函数作为参数来自定义排序规则或操作逻辑。
  • 回调函数: 仿函数可以作为回调函数,用于事件处理、异步编程等场景。
  • 实现策略模式: 仿函数可以用于实现策略模式,将不同的算法封装在不同的仿函数类中。

示例:

#include <iostream>

// 定义一个仿函数类,用于比较两个整数的大小
struct CompareGreater {
  bool operator()(int a, int b) const {
    return a > b;
  }
};

int main() {
  CompareGreater compare; 
  
  int x = 5, y = 3;

  // 使用仿函数对象进行比较
  if (compare(x, y)) {
    std::cout << x << " 大于 " << y << std::endl;
  } else {
    std::cout << x << " 小于等于 " << y << std::endl;
  }

  return 0;
}

在这个例子中,CompareGreater 类就是一个仿函数类,它定义了 operator() 运算符,用于比较两个整数的大小。通过创建 CompareGreater 类的对象,我们可以像调用函数一样使用它来进行比较操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值