c – 在C中模拟std :: bind

前端之家收集整理的这篇文章主要介绍了c – 在C中模拟std :: bind前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在使用std :: bind来提供回调,同时通过首先绑定一些参数来抽象一些逻辑.即
void start() {

    int secret_id = 43534;

    //Bind the secret_id to the callback function object
    std::function<void(std::string)> cb = std::bind(&callback,secret_id,std::placeholders::_1);

    do_action(cb);

}

void do_action(std::function<void(std::string)> cb) {

    std::string result = "hello world";
    //Do some things...

    //Call the callback
    cb(result);
}

void callback(int secret_id,std::string result) {

    //Callback can now do something with the result and secret_id

}

所以在上面的例子中,do_action不需要知道secret_id,而其他函数可以重用它而不需要自己的secret_id.当do_action是某种异步操作时,这尤其有用.

我的问题是,有没有办法只使用C将参数值绑定到函数指针?

如果不是通过模拟std :: bind那么还有另一种方法将数据从first()传递给callback()而不会使中性do_action()复杂化吗?

解决方法

C号不允许您直接执行此操作.

在C中,处理回调的标准方法是使用上下文指针:

void register_callback(void (*cback)(void *context,int data),void *context);

这意味着除了回调应该处理的普通参数(在上面的例子中是一个整数)之外,你将传递一个接受void *的函数,你还将传递一个你想要传回的void *.

此void *通常指向一个结构,该结构将包含回调中所需的所有额外参数或数据,并且使用此方法,库不依赖于此上下文的内容.如果回调不需要任何上下文,则只需将NULL指针作为上下文传递,并在从库中调用时忽略第一个参数.

有点像hackish和形式上不安全的东西,但有时会做的是,如果上下文是一个符合void *(例如整数)大小的简单数据,如果你的环境不会有问题,你可以欺骗通过传递一个假的void *只是一个整数,并在从库中调用时将它转换回整数(这可以节省调用者分配上下文并管理其生命周期).

关于如何欺骗语言以避免这种限制(仍然留在便携式C的领域)我可以想到一些黑客:

首先,我们分配一个双参数回调和上下文数据池

void (*cbf[6])(int,int);
int ctx[6];

然后我们编写(或宏生成)我们希望注册函数,并调用两个参数版本.

void call_with_0(int x) { cbf[0](ctx[0],x); }
void call_with_1(int x) { cbf[1](ctx[1],x); }
void call_with_2(int x) { cbf[2](ctx[2],x); }
void call_with_3(int x) { cbf[3](ctx[3],x); }
void call_with_4(int x) { cbf[4](ctx[4],x); }
void call_with_5(int x) { cbf[5](ctx[5],x); }

我们还将它们存储在一个池中,在那里它们被分配和解除分配:

int first_free_cback = 0;
int next_free_cback[6] = {1,2,3,4,5,-1};

void (*cbacks[6])(int) = { call_with_0,call_with_1,call_with_2,call_with_3,call_with_4,call_with_5 };

然后绑定第一个参数我们可以做类似的事情

void (*bind(void (*g)(int,int),int v0))(int)
{
    if (first_free_cback == -1) return NULL;
    int i = first_free_cback;
    first_free_cback = next_free_cback[i];
    cbf[i] = g; ctx[i] = v0;
    return cbacks[i];
}

但必须明确释放绑定函数

int deallocate_bound_cback(void (*f)(int))
{
    for (int i=0; i<6; i++) {
        if (f == cbacks[i]) {
            next_free_cback[i] = first_free_cback;
            first_free_cback = i;
            return 1;
        }
    }
    return 0;
}

猜你在找的C&C++相关文章