我可以将Functor类(重载operator())传递给需要函数指针的函数吗?如何

时间:2018-11-09 08:42:21

标签: c++ boost

此代码在这里工作正常。它喊
真的!
错!

#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代替函数指针”之类的解决方案不在桌面上。

4 个答案:

答案 0 :(得分:2)

回调允许额外参数的传统方式是让用户提供额外的void*

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

bool run_callback(int a, int b, void* userData) {
    CallBack* c = reinterpret_cast<void*>(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);

答案 1 :(得分:0)

如果您不介意传递其他参数,则可以执行以下操作:

#include <iostream>
#include <functional>

template<typename T>
using callback = bool(T::*) (int, int);

template<typename T>
void print_result(T t, callback<T> handle, int first, int second) {
    if(handle == nullptr)
        return;

    if((t.*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), &Callback::operator(), 2, 3);
    print_result(Callback(true), &Callback::operator(), 2, 3);
}

答案 2 :(得分:0)

不更改print_result,您必须根据自变量向Callback发送不同的函数。

将单个bool参数移动为模板参数非常简单,但是如果存在无法constexpr构造的状态,则会变得笨拙。

template<bool type>
bool Callback (int foo, int bar);

template<>
bool Callback<true> (int foo, int bar)
{
    return foo > bar;
}

template<>
bool Callback<false> (int foo, int bar)
{
    return foo < bar;
}

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

如果需要根据运行时值进行选择

callback select_callback(bool type)
{
    return type ? Callback<true> : Callback<false>;
}

答案 3 :(得分:0)

如果您不能更改与社会工程学的接口并且不想使用全局变量,那么仍然可以独处。创建一个C型封闭/蹦床。当然,这在标准C或C ++中是不可行的,但是有(非便携式)库可以为您做到这一点。 FFCALL就是其中之一。可以找到一个示例here

一旦创建了一个关闭数据的闭包,您就会被设置。只需将数据作为您原始的boost / std函数的一个(指针),然后调用它即可。