Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ionic-framework/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/codeigniter/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 通过C&x2B+;方法作为函数指针_C++ - Fatal编程技术网

C++ 通过C&x2B+;方法作为函数指针

C++ 通过C&x2B+;方法作为函数指针,c++,C++,我有一个类方法: bool sendRequest(DataFieldList& requestParams, DataFieldList& responseParams, std::string context, void(*sendFailure)() = NULL); SeDebug是一个可选的函数指针,在我的C++类中,我有一个例子: sendRequest(param

我有一个类方法:

    bool sendRequest(DataFieldList& requestParams,
                     DataFieldList& responseParams,
                     std::string context, void(*sendFailure)() = NULL);

SeDebug是一个可选的函数指针,在我的C++类中,我有一个例子:

    sendRequest(paramList, responseList, "Could not set background lighting control brightness limit", HBCMaxBrightnessLimitSendFailure);
HBCMaxBrightnessLimitSendFailure在类中声明为私有方法:

    void HBCMaxBrightnessLimitSendFailure();
当我构建此应用程序时,会出现以下错误:

    lightingsystemcomponent.cpp(969): error C3867: 'Lighting::SystemComponent_impl::HBCMaxBrightnessLimitSendFailure': function call missing argument list; use '&Lighting::SystemComponent_impl::HBCMaxBrightnessLimitSendFailure' to create a pointer to member
我还尝试:

    sendRequest(paramList, responseList, "Could not set background lighting control brightness limit", HBCMaxBrightnessLimitSendFailure());
这将错误更改为:

    lightingsystemcomponent.cpp(969): error C2664: 'bool Lighting::SystemComponent_impl::sendRequest(DataFieldList &, DataFieldList &,std::string,void (__cdecl *)(void))' : cannot convert argument 4 from 'void' to 'void (__cdecl *)(void)'
void类型的表达式无法转换为其他类型

我已经做了一些改变,并尝试实施斯宾塞提出的建议,新原型:

    bool sendRequest(DataFieldList& requestParams,
                     DataFieldList& responseParams,
                     std::string context,
                     std::function<void()> sendFailure = NULL);
下面是调用此例程和我传递的回调函数的类的示例:

    void component::onFailure() {
        ...Do something...
    }

    void component::update() {
        ... Some set-up to build paramlist ...
        LightingEngine* engine = getLightingEngine();
        assert(engine != nullptr);
        engine->sendRequest(&paramList, &responseList, "Some context text", [this]()->void { onFailure(); });            
    }
编辑:

如果您可以更改SeNeDebug的签名,并且使用的是相当现代的C++(11或更高),那么我会选择<代码> STD::函数< /C> > /P>

#include <functional>

bool sendRequest(DataFieldList& requestParams,
                     DataFieldList& responseParams,
                     std::string context, std::function<void()> sendFailure = nullptr);
bool sendRequest(DataFieldList& requestParams,
                 DataFieldList& responseParams,
                 std::string context, 
                 const std::function<void()> &sendFailure = nullptr);
或不带lambda但带bind:

sendRequest(paramList, responseList, "Could not set background lighting control brightness limit", std::bind(&Lighting::SystemComponent_impl::HBCMaxBrightnessLimitSendFailure,this));
旧帖子:

试试编译器告诉你的

&Lighting::SystemComponent_impl::HBCMaxBrightnessLimitSendFailure
因此:


成员函数不能直接转换为函数指针,因为它具有调用它的对象的隐式参数(您将其视为成员中的
this
指针)。解决这个问题并不像我想象的那么容易


最佳解决方案是什么,取决于您的用例。如果调用者和被调用者都是成员函数,并且确实依赖于从中调用它们的对象(这两者都是相同的),则添加另一个成员函数指针作为参数。如果传递的成员函数不依赖于其对象,则将其设为静态,这样就没有问题了。对于介于两者之间的所有内容,它都会变得棘手。

非静态类成员函数不同于非类函数,因为它需要类的实例才能工作。在你的声明中

bool sendRequest(DataFieldList& requestParams,
                 DataFieldList& responseParams,
                 std::string context, void(*sendFailure)() = NULL);
sendFailure
被声明为非成员函数。如果必须这样做,您将永远无法绑定到非静态成员函数

最简单的方法是将
HBCMaxBrightnessLimitSendFailure
声明为
static
,甚至将其全部移出类,但这仅在不依赖于类的状态时才起作用

假设您有许多不同的失败函数,它们在不同的时间传递。如果只有一个,不要传入函数指针。而是通过一个bool:

bool sendRequest(DataFieldList& requestParams,
                 DataFieldList& responseParams,
                 bool sendFailure = false)
{
  // ...
  if (sendFailure) HBCMaxBrightnessLimitSendFailure();
  // ...
}
可以使用指向成员函数的指针,但需要类的实例。如果
sendRequest
HBCMaxBrightnessLimitSendFailure
属于同一类别,请使用

bool sendRequest(DataFieldList& requestParams,
                 DataFieldList& responseParams,
                 std::string context, 
                 void(lightingsystemcomponent::*sendFailure)()= 0);
{
 if (sendFailure !=0) this ->*sendFailure();
}

...
sendRequest (request, response, ctxt, &HBCMaxBrightnessLimitSendFailure); 
最灵活的方法(以少量开销为代价)是将
sendFailure
参数重新声明为
std::function

bool sendRequest(DataFieldList& requestParams,
                 DataFieldList& responseParams,
                 std::string context, std::function<void()> sendFailure);
如果函数参数需要是一个裸函数,例如为了传递给一个C API调用,事情就会变得一团糟。带有捕获的lambda永远不会起作用。这种“有状态”lambda是一个动态创建的类,函数指针和捕获值作为数据成员。并且不能将C++类传递到C函数中。

但是您需要一个类的实例来使用member函数!啊!它唯一需要的是从函数中访问类的全局实例:

    void LightingEngine::sendRequest(DataFieldList& requestParams,
                                     DataFieldList& responseParams,
                                     std::string context,
                                     std::function<void()> sendFailure) {
    if ( sendFailure != NULL ) {
        sendFailure();
    }
class lightingsystemcomponent
{
    static lightingsystemcomponent*api_context;
    static void HBCMaxBrightnessLimitSendFailure()
    {
      api_context-> something();
    }
    bool sendRequest(DataFieldList& requestParams,
                 DataFieldList& responseParams,
                 std::string context, void(*sendFailure)() = NULL);
};
// ...
api_context = this;
sendRequest(request, response, "context", HBCMaxBrightnessLimitSendFailure());

这类似于有状态lambda为您所做的事情,但您可以将其传递到C库,但需要付出一定的代价。

您可以将
sendFailure
声明为成员函数指针

bool sendRequest(DataFieldList& requestParams,
                 DataFieldList& responseParams,
                 std::string context, 
                 void(Lighting::SystemComponent_impl::*sendFailure)() = nullptr);
这将允许你写一行很长的字:

sendRequest(paramList, responseList, "Could not set background lighting control brightness limit", &Lighting::SystemComponent_impl::HBCMaxBrightnessLimitSendFailure);

另一个选项是使用
std::function

#include <functional>

bool sendRequest(DataFieldList& requestParams,
                     DataFieldList& responseParams,
                     std::string context, std::function<void()> sendFailure = nullptr);
bool sendRequest(DataFieldList& requestParams,
                 DataFieldList& responseParams,
                 std::string context, 
                 const std::function<void()> &sendFailure = nullptr);

执行回调的惯用“C++方法”是使用函数模板。这类似于使用
std::function
,但性能要高得多

template <typename Func>
bool sendRequest(DataFieldList& requestParams,
                 DataFieldList& responseParams,
                 std::string context, 
                 Func sendFailure);
然后像这样调用
sendRequest

sendRequest(paramList, responseList, "Could not set background lighting control brightness limit", [this]{ HBCMaxBrightnessLimitSendFailure() });
sendRequest(paramList, responseList, "Could not set background lighting control brightness limit", [this]{ HBCMaxBrightnessLimitSendFailure() });

如果您将
void(*sendFailure)(
函数指针更改为
std::function
,那么我认为您可以执行您想要的操作:

void printFunc(int a, std::function<void(void)> f)
{
    std::cout << a << '\t';
    if (f)
        f();
    else
        std::cout << "f is null" << std::endl;
}

void testFunc()
{
    std::cout << "testFunc" << std::endl;
}

class A
{
private:
    void privatePrint() { std::cout << "privatePrint " << a << std::endl; }
    int a;

public:
    A(int i) : a { i } {}
    void print()
    {
        printFunc(a, [this]() {this->privatePrint();} );
    }
};

class B
{
private:
    static void staticPrint() { std::cout << "staticPrint" << std::endl; }
    int b;

public:
    B(int i) : b{ i } {}
    void print()
    {
        printFunc(b, staticPrint);
    }
};

struct C
{
    void operator()() { std::cout << "operator()" << std::endl; }
};

int main()
{
    printFunc(1, testFunc);

    A a{ 2 };
    a.print();

    B b{ 3 };
    b.print();

    printFunc(4, nullptr);

    C c;
    printFunc(5, c);
}

这只在方法是静态的情况下有效(它似乎不是来自OPs问题)。啊,sry,你当然是对的@Kerndog73。我会相应地更新它。那怎么办呢?可以取函数指针
std::mem_fn
,但它有另一个参数指向调用对象(我们将隐式参数显式化)。如果您将一个对象绑定到该对象,它将是有状态的,并且您再次无法获取函数指针。这是否回答了您的问题?请不要这样故意破坏你的问题,尤其是当人们费心回答的时候。我已经为您回滚了您的编辑。@TobySpeight,很公平,是无知和贬损性的评论导致我想要关闭或删除它,但我看到这些评论现在已经被删除,谢谢。我想问题是您使用的是
NULL
而不是
nullptr
@Kerndog73,非常好,很好,谢谢@这和我的答案很相似。你认为什么不对?我投了赞成票。@Splaten我添加了一些可能性。谢谢你的时间和努力,我编辑了我的原始帖子,以显示我试图实施你的建议,你能看出有什么问题吗?
bool sendRequest(DataFieldList& requestParams,
                 DataFieldList& responseParams,
                 std::string context);
sendRequest(paramList, responseList, "Could not set background lighting control brightness limit", [this]{ HBCMaxBrightnessLimitSendFailure() });
void printFunc(int a, std::function<void(void)> f)
{
    std::cout << a << '\t';
    if (f)
        f();
    else
        std::cout << "f is null" << std::endl;
}

void testFunc()
{
    std::cout << "testFunc" << std::endl;
}

class A
{
private:
    void privatePrint() { std::cout << "privatePrint " << a << std::endl; }
    int a;

public:
    A(int i) : a { i } {}
    void print()
    {
        printFunc(a, [this]() {this->privatePrint();} );
    }
};

class B
{
private:
    static void staticPrint() { std::cout << "staticPrint" << std::endl; }
    int b;

public:
    B(int i) : b{ i } {}
    void print()
    {
        printFunc(b, staticPrint);
    }
};

struct C
{
    void operator()() { std::cout << "operator()" << std::endl; }
};

int main()
{
    printFunc(1, testFunc);

    A a{ 2 };
    a.print();

    B b{ 3 };
    b.print();

    printFunc(4, nullptr);

    C c;
    printFunc(5, c);
}
1       testFunc
2       privatePrint 2
3       staticPrint
4       f is null
5       operator()