首页 > 解决方案 > 我可以将 Functor 类(重载 operator())传递给需要函数指针的函数吗?如何

问题描述

这段代码在这里工作得很好。它是
真的!
错误的!
正如它应该

#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>

//typedef bool(callback) (int, int);
typedef boost::function<bool(int, int)> callback;

void print_result(callback handle, int first, int second)
{
    if(handle == nullptr)
        return; 

    if(handle(first, second))
        std::cout << "True!\n";
    else
        std::cout << "False!\n";
}

class Callback
{
public:
    Callback(bool type) : m_type(type)
    {}
    bool operator() (int foo, int bar)
    {
        return m_type ? foo > bar : foo < bar;
    }
private:
    bool m_type;
};

int main()
{   
    print_result(Callback(false), 2, 3);
    print_result(Callback(true), 2, 3);
    return 0;
}

但不幸的是,我必须使它与旧的函数指针一起工作。我从来没有在我的实践中使用它们,我对它们了解不多。很明显,签名“bool operator() (int foo, int bar)”不容易转换为“bool(callback) (int, int)”。

我从 gcc 得到的错误代码:

prog.cc: In function 'int main()':
prog.cc:34:18: error: cannot convert 'Callback' to 'bool (*)(int, int)'
     print_result(Callback(false), 2, 3);
                  ^~~~~~~~~~~~~~~
prog.cc:8:28: note:   initializing argument 1 of 'void print_result(bool (*)(int, int), int, int)'
 void print_result(callback handle, int first, int second)
                   ~~~~~~~~~^~~~~~
prog.cc:35:18: error: cannot convert 'Callback' to 'bool (*)(int, int)'
     print_result(Callback(true), 2, 3);
                  ^~~~~~~~~~~~~~
prog.cc:8:28: note:   initializing argument 1 of 'void print_result(bool (*)(int, int), int, int)'
 void print_result(callback handle, int first, int second) 

有什么办法解决吗?顺便说一句,我不介意有不同的解决方案。例如,可以使用“boost::bind”传递 bool 参数,但绑定也不起作用。出于同样的原因。
想法,有人吗?提前致谢!

注意:我无法更改“print_result”函数的签名。诸如“使用 X 而不是函数指针”之类的解决方案不在讨论范围内。

标签: c++boost

解决方案


回调允许额外参数的传统方法是拥有void*用户提供的额外参数。

using callback = bool (int, int, void* userData);

bool run_callback(int a, int b, void* userData) {
    CallBack* c = reinterpret_cast<CallBack*>(userData);

    return (*c)(a, b);
}

CallBack t(true);
Register(&run_callback, &t); // Would call later run_callback(2, 3, &t);

如果您无法更改签名,则可以使用 global 来传递该额外参数,因此有一些限制。

Callback* global = nullptr;

bool RunCallBack(int foo, int bar)
{
    assert(global != nullptr);
    return (*global)(foo, bar);
}

接着

Callback f(false);
Callback t(true);

global = &f;
print_result(&RunCallBack, 2, 3);
global = &t;
print_result(&RunCallBack, 2, 3);

推荐阅读