模拟的std ::绑定使用C [英] Emulating std::bind in C

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

问题描述

我使用的std ::绑定,以提供一个回调,同时通过第一结合一些参数提取一些逻辑。即。

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 ::绑定则有另一种方式,而不中性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);

这意味着你会通过,将接受除了回调应处理(在上述情况下的整数)正常参数的无效* 函数,你也将传递一个无效* 要被传回。

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.

无效* 通常指向结构将包含所有你在需要额外的参数或数据回调使用这种方法库不依赖于这样的背景下是什么。如果回调不需要任何情况下,你只是传递一个NULL指针作为背景并忽略第一个参数时,从库中被调用。

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.

东西是种hackish的正式不安全,但它有时做的是,如果环境是适合一个无效* (例如:一个整数的大小的简单数据),如果你的环境是不会有它的问题,你可以通过传递一个假的欺骗库无效* 这仅仅是一个整数,你将其转换回一个整数从库中被调用时(这从分配的背景和管理其使用寿命避免了调用者)。

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).

在我怎样怎样欺骗语言来避免此限制(便携式C的土地仍然保留),可以认为,一些黑客:

On how to how to trick the language to avoid this limitation (still remaining in the land of portable C) I can think some hack:

首先,我们分配两个论点回调和上下文数据池

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

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

然后我们写(或宏生成),我们想要注册功能和将调用两个参数的版本。

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

这篇关于模拟的std ::绑定使用C的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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