我可以使用std :: bind将指向成员函数的指针转换为指向函数的指针吗?

问题描述 投票:2回答:2

我想将成员函数作为回调传递。回调是一个基本的函数指针。

所以我有类似的东西:

h文件:

void (*pRequestFunc) (int someint) = 0;
void RegisterRequestCallBack(void (*requestFunc) (int someint))
{
    pRequestFunc = requestFunc;
}

class A
{
    void callBack(int someint);
}

Cpp文件:

RegisterRequestCallBack(&A::callBack); // This does not work.

注意我试图从我的更大的例子中提取这个例子并删除所有其他的东西 - 所以它可能不完美。

据我所知,问题是成员函数指针真的(在引擎盖下)有一个额外的参数(和实例 - 即this)并且与普通函数指针不兼容。

RegisterRequestCallBack()实际上不是我的代码 - 所以我不能改变它。

所以我读到boost :: bind可以做我需要的 - 我希望c ++ 11 std :: bind可以做同样的事情 - 但我无法弄清楚如何使用它来有效地从一个标准函数指针成员函数指针...

我想要的是:

std::bind(&A::callBack) ......就我而言,我对网上示例的理解很差:(

c++ bind member-functions
2个回答
2
投票

NathanOliver的评论是正确的,你的怀疑大多是正确的。确切地说,如何指定成员函数的指针是如何工作的,但是将this作为隐藏参数包含起来的作用大多数都有效。你只需要一些额外的继承工作和指向virtual函数的指针(是的,你也可以使用它们的地址)。

现在,通常回调包括您控制下的void*参数,您可以使用它来传递A*。在这些情况下,您可以编写一个包装器(static)函数,将void*强制转换回A*并执行&A::callback的实际调用。

情况并非如此。注册只需一个功能,无需数据。为了在现实生活中实现这一点,你必须采用激烈的解决方案 - 而不是可移植的C ++。一种这样的方法是动态生成程序集(!)。您在运行时创建编译的等效项

void __trampoline_0x018810000 (int i)
{
   A* __this = reinterpret_cast<A*>(0x018810000);
   __this->callback(i);
}

正如您所看到的,您必须为每个A*值生成一个蹦床,并且管理这些蹦床的生命周期是一个主要的痛苦。


0
投票

为了能够绑定到您需要执行的成员函数:

std::function<void(int)> function = std::bind(&A::foo, this, std::placeholders::_1);

或者在你的情况下:

RegisterRequestCallBack(std::bind(&A::callback, this, std::placeholders::_1));

但在我看来,实现这一目标最明确的方法是使用lambda函数。在这里你有一个例子来做类似的东西,可以激励你:

#include <array>
#include <map>
#include <vector>
#include <functional>
#include <iostream>

class TaskManager {
    public:
        using task_t = std::function<void()>;

        void run();
        void addTask(task_t task);

    private:
        std::vector<task_t> _tasks;
};

void TaskManager::run() {
    for (auto& task : _tasks) {
        task();
    }
}

void TaskManager::addTask(task_t task) {
    _tasks.push_back(task);
}

class Example {
    public:
        Example(){
            taskManager.addTask([this]() {
                task1();
            });
            taskManager.addTask([this,a=int(4)](){
                task2(a);
            });
        }

    TaskManager taskManager;

    private:
        void task1(){ std::cout << "task1!\n"; }
        void task2(int a){ std::cout << "task2 says: " << a << "\n"; }
};

int main() {
    Example example;
    example.taskManager.run();
}

哪个输出:

task1!
task2 says: 4
© www.soinside.com 2019 - 2024. All rights reserved.