其他分享
首页 > 其他分享> > c – 使用std :: function进行回调的Alterantive

c – 使用std :: function进行回调的Alterantive

作者:互联网

目前我正在尝试一个基本上具有以下功能的代码:

void f(int x) { cout << "f("<<x<<")" << endl; }

class C
{
public:
   void m(int x) { cout << "C::m("<<x<<")" << endl; }
};

class C2
{
public:
   void registerCallback(function<void(int)> f)
   {
      v.push_back(f);
   }

private:
   vector<function<void(int)>> v;

   void callThem()
   {
      for (int i=0; i<v.size(); i++)
      {
         v[i](i);
      }
   }
};

int main()
{
   C2 registrar;

   C c;
   registrar.registerCallback(&f); // Static function
   registrar.registerCallback(bind(&C::m, &c, placeholders::_1)); // Method

   return 0;
}

这非常有效.但是我遇到了这种模式.我想检查一个回调是否已经注册,我希望能够通过从向量中删除它来取消注册回调.我刚刚了解到无法比较std :: function对象,这意味着无法在容器中搜索它们的存在.

所以我需要另一种选择.当然我想保持编译时类型检查和注册任意类方法的能力.

如何实现允许取消注册回调和检查双重注册的类似解决方案?我需要接受任何权衡吗?

解决方法:

根本问题是大多数功能对象无法比较.虽然可以比较普通函数指针和具有相等运算符的用户定义函数对象,但是lambdas,std :: bind()等的结果却不能.使用函数对象的地址来识别它们通常不是合适的方法,因为对象往往被复制.可以使用std :: reference_wrapper< Fun>避免复制它们但存储在std :: function< F>中的对象仍然会有不同的地址.

使用C 11可变参数模板,可以非常轻松地创建自定义版本的std :: function< ...>提供比较设施.甚至可能有两个版本:

>一个版本接受任意函数对象,但显然只能比较可比较的函数对象:取决于构造函数参数是否提供了相等运算符,使用了合适的基类.
>一个版本总是提供工作比较,显然,不能与不等同的对象一起使用.

后者稍微容易定义,看起来像这样:

template <typename...> class comparable_function;
template <typename RC, typename... Args>
class comparable_function<RC(Args...)> {
    struct base {
        virtual ~base() {}
        virtual RC    call(Args... args) = 0;
        virtual base* clone() const = 0;
        virtual bool  compare(base const*) const = 0;
    };
    template <typename Fun>
    struct concrete: base {
        Fun fun;
        concrete(Fun const& fun): fun(fun) {}
        RC call(Args... args) { return this->fun(args...); }
        base* clone() const { return new concrete<Fun>(this->fun); }
        bool compare(base const* other) const {
             concrete const* o = dynamic_cast<concrete<Fun>>(other);
             return o && this->fun == o->fun;
        }
    };
    std::unique_ptr<base> fun;
public:
    template <typename Fun>
    comparable_function(Fun fun): fun(new concrete<Fun>(fun)) {}
    comparable_function(comparable_function const& other): fun(other.fun->clone()) {}
    RC operator()(Args... args) { return this->fun->call(args); }
    bool operator== (comparable_function const& other) const {
        return this->fun->compare(other.fun.get());
    }
    bool operator!= (comparable_function const& other) { return !(this == other); }
};

我想,我已经忘记(和/或错误)某些东西,而不是那就是需要的东西.对于可选的可比较版本,您有两个版本的混凝土:一个是上面实现的,另一个总是返回false.根据构造函数中的Fun是否有运算符==,您可以创建一个或另一个.

标签:std-function,stdbind,c,c11,callback
来源: https://codeday.me/bug/20190830/1766693.html