在C中模拟std :: bind [英] Emulating std::bind in C

查看:107
本文介绍了在C中模拟std :: bind的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用std :: bind提供一个回调,同时通过绑定一些参数来抽象一些逻辑。即

I'm using std::bind to provide a callback while abstracting some logic by binding some parameters first. i.e.

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是某种异步操作。

So in the above example, the do_action does not need to know about the secret_id and other functions can reuse it without having a secret_id of their own. This is especially useful when do_action is some kind of asynchronous operation.

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

My question is, is there a way to bind parameter values to function pointers using only C?

如果不是通过模拟std :: bind,还有另一种方法来传递数据从first()到callback(),而不会使中性do_action >

If not by emulating std::bind then is there another way to pass data from first() to callback() without complicating the neutral do_action()?

推荐答案

否。 C不允许你直接这样做。

No. C doesn't allow you to do that directly.

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

In C the standard way to handle callbacks is using context pointers:

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

这意味着您将传递一个将接受 void * 除了回调应该处理的正常参数(在上面的情况下是一个整数),你还将传递一个 void *

this means that you will pass a function that will accept a void * in addition to the normal parameters that the callback should handle (in the above case an integer) and you will also pass a void * that you want to be passed back.

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

This void * normally points to a struct that will contain all the extra parameters or data you need in the callback and using this approach the library doesn't depend on what this context is. If the callback doesn't need any context you just pass a NULL pointer as context and ignore the first parameter when being called from the library.

有些东西是一种黑客和正式不安全,但有时做的是如果上下文是一个简单的数据,符合 void * (例如一个整数),如果你的环境不会有问题,你可以通过传递一个假的 void * 这只是一个整数,当从库中调用时,返回一个整数(这将保存调用者分配上下文和管理它的生命周期)。

Something that is kind of hackish and formally unsafe but it's sometimes done is that if the context is a simple data that fits the size of a void * (e.g. an integer) and if your environment is not going to have problems with it you can trick the library by passing a fake void * that is just an integer and you convert it back to an integer when being called from the library (this saves the caller from allocating the context and managing its lifetime).

关于如何欺骗语言避免

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

First we allocate a pool of two-arguments callbacks and context data

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

然后我们写(或宏生成)我们想要注册的函数, -arguments versions。

then we write (or macro-generate) functions that we wish to register and that will call the two-arguments versions.

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); }

我们还将它们存储在池中,并在其中分配和释放:

We also store them in a pool where they're allocated and deallocated:

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 };

然后绑定第一个参数,我们可以做

Then to bind the first parameter we can do something like

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];
}

但绑定函数也必须显式释放

but bound functions must also be explicitly deallocated

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中模拟std :: bind的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆