C++ 将带有参数的回调函数传递给函数

C++ 将带有参数的回调函数传递给函数,c++,c++11,function-pointers,void-pointers,C++,C++11,Function Pointers,Void Pointers,我想调用下面的函数,并给它传递一个带参数的函数。这样做的目的是,它应该使用我指定的参数调用函数,以便我知道是什么触发了函数(在这种情况下,Raspberry Pi上的gpio引脚) 目前我有: for ( int i = 0; i < myValues.size(); ++i ) { int myValue = myValues[ i ]; wiringPiISR( myValue, INT_EDGE_RISING, &myCallback( myValue ) )

我想调用下面的函数,并给它传递一个带参数的函数。这样做的目的是,它应该使用我指定的参数调用函数,以便我知道是什么触发了函数(在这种情况下,Raspberry Pi上的gpio引脚)

目前我有:

for ( int i = 0; i < myValues.size(); ++i )
{
    int myValue = myValues[ i ];
    wiringPiISR( myValue, INT_EDGE_RISING, &myCallback( myValue ) );
}
for(int i=0;i
尽管这给了我以下错误:

错误:一元'&'操作数需要左值

我真的无法理解,就我的理解而言,myValue是左值还是非左值

这是我想做的吗?如果是,怎么做?
函数wiringPiISR来自一个名为wiringPi的库,我希望尽可能避免对它进行修改。

如果您有c++11,我建议使用
std::function
-它相当干净


否则,您的函数签名是错误的。您需要类型为
void(int)
的回调,但您的函数需要
void()
您需要使用
std::function
std::bind

将函数签名更改为

int wiringPiISR (int pin, int edgeType,  std::function<void()> func);
这样做的目的是创建一个
std::function
对象(即可调用对象),该对象包装函数并将所需值保持在其状态


这只适用于
C++11
及更新版本。

如果
myValue
是您可以在编译时决定的内容,您可以静态设置它并使用中间函数传入

void myCallbackHelper() {
    static constexpr int myValue = 3;
    myCallback(myValue);
}

wiringPiISR(myValue, INT_EDGE_RISING, &myCallbackHelper);
如果您需要在运行时确定
myValue
,您仍然可以完成这项工作,但并不是真正的线程安全

int& getMyValue() {
    static int myValue;
    return myValue;
}

void setMyValue(int i) {
    getMyValue() = i;
}

void myCallbackHelper() {
    myCallback(getMyValue());
}
然后设置它并调用

setMyValue(3);
wiringPiISR(myValue, INT_EDGE_RISING, &myCallbackHelper);

我查了一下wiringPiISR,发现它是某种api调用,所以我假设您无法更改它

话虽如此,大多数带有函数指针回调的api调用看起来像这样是有原因的

void setCallback( void (*function)(void* data), void* userdata);
这允许人们转换他们的
struct{blabla}数据
来添加一些userdata,当调用函数时,会传递它


因此,基本上,除了使用静态变量进行黑客攻击外,你不能传递任何参数。

你可以将imreal和Ryan Haining的答案结合起来,比如这样的

std::function<void()> cbfunc;

void myCallback()
{
  cbfunc();
}
void myWiringPiISR(int val, int mask, std::function<void()> callback)
{
  cbfunc = callback;
  wiringPiISR(val, mask, &myCallback);
}
无需修补程序库,您可以使用所有绑定/函数。我会让你找到解决线程安全问题的方法

它是如何工作的?简单地说,“std::bind”是将一个函数及其参数绑定到一个std:function对象中,然后可以从myCallback函数“调用”该对象,myCallback函数充当您传递的回调的填充。我以前给回调函数起过一个令人困惑的名字,但这次编辑希望能解决这个问题。

你可以“吐”这个函数。这不需要用户定义的可变全局变量,并且是线程安全的,除非您的编译器支持多线程,但不支持基本上不可用的每线程异常

myWiringPiISRWrapper(Value value, int edge, std::function<void()> func) {
    try {
        throw &func;
    } catch(...) {
        myWiringPiISR(value, edge, [] {
            try {
                throw;
            } catch(std::function<void()>* func) { 
                (*func)();
            }
        });
    }
}
myWiringPiISRWrapper(Value-Value,int-edge,std::function func){
试一试{
投掷&功能;
}捕获(…){
myWiringPiISR(值,边,[]{
试一试{
投掷;
}catch(std::function*func){
(*func)();
}
});
}
}

这是恶心和缓慢,但它完全封装,我认为这是一个值得的优势。请注意,只有在调用
myWiringPiISR
返回后从未执行回调时,此操作才有效。在这种情况下,您当然可以使用您想要的任何绑定状态进行回调。

您是指一个函数,它接受一个参数,但有一个预定义的值,这样就可以在没有参数的情况下调用它吗?不太清楚您的意思,但我想是这样的。我所要做的就是给wiringPiISR一个函数来调用我提供的参数,这样wiringPiISR就可以使用提供的参数来调用该函数。我猜我在这里使用了错误的术语,编辑了问题。
&myCallback(myValue))
&(myCallback(myValue))
相同,因此您在
myCallback的返回值上取地址。由于
myValue
已经是第一个参数,因此您可能只需要传递
&myCallback
。但是我们不能从当前的上下文中判断。所以如果不修改wiringPiISR函数,这是不可能的?我真的很想避免这种情况,因为这意味着每次更新库时(这种情况经常发生),我都需要对库中包含的库进行修补。有必要对其进行更改。谢谢,如果这确实是我唯一的选择,我会尝试一下。这不等于为每个可能的回调创建一个专用函数吗?如果回调需要参数,并且需要使用函数指针
void(*)(void)
,那么您的选项将受到限制,轻度痛苦我会对那些轻度痛苦的选项感兴趣,每次我更新时修补库wiringPiISR将是一种持续的轻度痛苦,所以我宁愿有一次这样的痛苦。将这个答案与@imreals:Make you shim function调用一个在setmyvalue中赋值的std::function合并。@professorblacks这是一个温和的答案painful@RyanHaining-谢谢。Globals确实很蹩脚,但我不想把答案弄得更混乱。你能解释一下这里发生了什么吗?这有点超出我的知识范围。回调如何获取myValue参数?您的myCallback()不接受任何参数。谢谢,编辑非常有用!这样做听起来有点疯狂,但我很乐意将此作为解决方案。尽管我想知道为什么这不是线程安全的?在过去的几分钟里,我一直在思考这个问题,但我真的不明白为什么会有问题,据我所知,wiringPiISR函数没有写入任何内容。如果有两个函数同时调用mywirinpisr,那么线程就不安全了
std::function<void()> cbfunc;

void myCallback()
{
  cbfunc();
}
void myWiringPiISR(int val, int mask, std::function<void()> callback)
{
  cbfunc = callback;
  wiringPiISR(val, mask, &myCallback);
}
void myActualCallback(int v)
{
  ... do something...
}

myWiringPiISR(myValue, INT_EDGE_RISING, std::bind(myActualCallback, myValue));
myWiringPiISRWrapper(Value value, int edge, std::function<void()> func) {
    try {
        throw &func;
    } catch(...) {
        myWiringPiISR(value, edge, [] {
            try {
                throw;
            } catch(std::function<void()>* func) { 
                (*func)();
            }
        });
    }
}