Reputation: 1259
I want to call the following function and pass it a function with a parameter. The purpose of that is that it should call the function with my specified parameter so I know what triggered the function (in that case a gpio pin on the Raspberry Pi).
int wiringPiISR( int pin, int edgeType, void (*function)( void ) );
Currently I have:
for ( int i = 0; i < myValues.size(); ++i )
{
int myValue = myValues[ i ];
wiringPiISR( myValue, INT_EDGE_RISING, &myCallback( myValue ) );
}
Though this is giving me the following error:
error: lvalue required as unary ‘&’ operand
Which I can't really understand as to my understanding, myValue is an lvalue or is it not?
Is it what I want do even possible? If so how? The function wiringPiISR is from a library called wiringPi and I would like to avoid modifying it as much as possible.
Upvotes: 3
Views: 20627
Reputation: 146910
You can "vomit" the function. This doesn't require a user-defined mutable global variable and is thread-safe, unless you have a compiler that supports multiple threads but not per-thread exceptions which would be basically unusable.
myWiringPiISRWrapper(Value value, int edge, std::function<void()> func) {
try {
throw &func;
} catch(...) {
myWiringPiISR(value, edge, [] {
try {
throw;
} catch(std::function<void()>* func) {
(*func)();
}
});
}
}
It's disgusting and slow, but it's totally encapsulated which I think is a worthwhile upside. Note that this only works if the callback is never executed after the call to myWiringPiISR
returns. In this case you can of course have a callback with whatever bound state you desire.
Upvotes: 3
Reputation: 68023
You could combine the answers from imreal and Ryan Haining something like this.
std::function<void()> cbfunc;
void myCallback()
{
cbfunc();
}
void myWiringPiISR(int val, int mask, std::function<void()> callback)
{
cbfunc = callback;
wiringPiISR(val, mask, &myCallback);
}
... and then use it...
void myActualCallback(int v)
{
... do something...
}
myWiringPiISR(myValue, INT_EDGE_RISING, std::bind(myActualCallback, myValue));
No need to patch library, and you can use all the bind/function goodness. I'll leave you to find a way around the thread safety issues...
How does it work? Put simply 'std::bind' is binding together a function and it's parameters into a single std:function object which can then be 'called' from the myCallback function which acts as a shim around the callback that you pass. I'd given the callback function a confusing name before, but this edit has hopefully fixed that.
Upvotes: 6
Reputation: 2220
I looked up wiringPiISR
and found that it is some sort of api call, so i am assuming you cannot change it.
Having said that, there is a reason most api-calls with a function-pointer-callback look sort of like this
void setCallback( void (*function)(void* data), void* userdata);
This allows people to cast their struct {blabla} data;
to add some userdata, and when the function is called, it is passed along.
So basically, apart from hacking stuff with static variables, you can't pass any arguments.
Upvotes: 2
Reputation: 36782
If myValue
is something you can decide at compile time, you could set it statically and use an intermediate function to pass in.
void myCallbackHelper() {
static constexpr int myValue = 3;
myCallback(myValue);
}
wiringPiISR(myValue, INT_EDGE_RISING, &myCallbackHelper);
If you need to determine myValue
at run time, you could still accomplish this, but not really thread-safely.
int& getMyValue() {
static int myValue;
return myValue;
}
void setMyValue(int i) {
getMyValue() = i;
}
void myCallbackHelper() {
myCallback(getMyValue());
}
Then set it and call
setMyValue(3);
wiringPiISR(myValue, INT_EDGE_RISING, &myCallbackHelper);
Upvotes: 3
Reputation: 10348
You need to use std::function
and std::bind
.
Change your function signature to
int wiringPiISR (int pin, int edgeType, std::function<void()> func);
Inside you can call the callback simply using func()
And your call to:
int myValue = 3;
wiringPiISR(myValue, INT_EDGE_RISING, std::bind(myCallback, myValue));
What this does is create a std::function
object (i.e. a callable) that wraps your function and keeps your desired value in its state.
This will only work on C++11
and newer.
Upvotes: 1
Reputation: 1246
If you have c++11, I suggest using std::function
- it's quite a bit cleaner.
If not, your function signature is wrong. You want a callback with the type void(int)
but your function takes a void()
Upvotes: 0