I have small Arduino project that using lambas:
typedef void(*keyboardKeyDelegate)(int);
void KeyboardKeyChange(int button, keyboardKeyDelegate onKeyChange);
void KeyboardKeyChange(int button, keyboardKeyDelegate onKeyChange)
{
// code...
}
void KeyboardKeyClick(int button, keyboardKeyDelegate onClick);
void KeyboardKeyClick(int button, keyboardKeyDelegate onClick)
{
// code...
}
.. next
bool r = true;
KeyboardKeyClick(KB_TOP, [&r](int state)
{
r = !r;
Serial.println("> KB_TOP CLICKED");
});
I have an error while compiling source:
no suitable conversion function from "lambda []void (int state)->void" to "keyboardKeyDelegate" exists
Maybe someone knows more about this error and help me to figured it out.
Your lambda has state and is thus not convertible to a functionpointer like the function argument.
You need to either remove the state from your lambda and recover it someway, or change the function to accept any callable by turning it into a template.
Related
For my microcontroller project I need custom timer with possibility to change interruption handler function. I created a Timer class for this.
I need to initialize ESP32 timer with function.
That is how I am trying to do this:
class Timer
{
private:
hw_timer_t* timer = nullptr;
std::function<void(void)>& onTimer;
public:
Timer(uint16_t intervalMs, std::function<void(void)>& newOnTimer): onTimer(newOnTimer)
{
timer = timerBegin(0, 40, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, intervalMs * 1000, true);
}
void start()
{
timerAlarmEnable(timer);
}
};
And timer initialization:
Timer t = Timer(250, []IRAM_ATTR(){
Serial.print("Tick ");
Serial.println(millis());
if(point)
{
point = false;
d.clearPixel(4, 4);
return;
}
point = true;
d.drawPixel(4,4);
});
But when I am launching it, I get:
sketch.ino: In constructor 'Timer::Timer(uint16_t, std::function<void()>&)':
sketch.ino:1161:35: error: cannot convert 'std::function<void()>*' to 'void (*)()'
timerAttachInterrupt(timer, &onTimer, true);
^~~~~~~~
In file included from /esp32/hardware/esp32/2.0.4/cores/esp32/esp32-hal.h:88,
from /esp32/hardware/esp32/2.0.4/cores/esp32/Arduino.h:36,
from sketch.ino.cpp:1:
/esp32/hardware/esp32/2.0.4/cores/esp32/esp32-hal-timer.h:39:53: note: initializing argument 2 of 'void timerAttachInterrupt(hw_timer_t*, void (*)(), bool)'
void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge);
~~~~~~~^~~~~~~~~
sketch.ino: At global scope:
sketch.ino:1341:16: error: expected primary-expression before '(' token
Timer t = Timer(250, []IRAM_ATTR(){
^
In file included from /esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/hal/esp32/include/hal/cpu_ll.h:18,
from /esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/hal/include/hal/cpu_hal.h:16,
from /esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/esp_hw_support/include/esp_cpu.h:14,
from /esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/esp_hw_support/include/soc/cpu.h:14,
from /esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/esp_hw_support/include/soc/spinlock.h:11,
from /esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/freertos/port/xtensa/include/freertos/portmacro.h:42,
from /esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/freertos/include/freertos/portable.h:51,
from /esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/freertos/include/freertos/FreeRTOS.h:63,
from /esp32/hardware/esp32/2.0.4/cores/esp32/Arduino.h:33,
from sketch.ino.cpp:1:
sketch.ino: In lambda function:
/esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/esp_common/include/esp_attr.h:150:46: error: expected '{' before '__attribute__'
#define _SECTION_ATTR_IMPL(SECTION, COUNTER) __attribute__((section(SECTION "." _COUNTER_STRINGIFY(COUNTER))))
^~~~~~~~~~~~~
/esp32/hardware/esp32/2.0.4/tools/sdk/esp32/include/esp_common/include/esp_attr.h:23:19: note: in expansion of macro '_SECTION_ATTR_IMPL'
#define IRAM_ATTR _SECTION_ATTR_IMPL(".iram1", __COUNTER__)
^~~~~~~~~~~~~~~~~~
sketch.ino:1341:24: note: in expansion of macro 'IRAM_ATTR'
Timer t = Timer(250, []IRAM_ATTR(){
^~~~~~~~~
sketch.ino: At global scope:
sketch.ino:1341:24: error: expected ')' before '__attribute__'
Timer t = Timer(250, []IRAM_ATTR(){
~ ^
)
Error during build: exit status 1
I am not expert in C++, so I totally don't understand what I need to do there to fix it.
Could anyone who knows what to do tell me about this, please?
Thank you in advance.
The signature of timerAttachInterrupt is
void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge);
Like the error says, you cannot convert a std::function<void()>* to a void(*)(). While std::function<...> is a class that can wrap pretty much any callable object and store the data needed (eg. the variables captured in a lambda), function pointers are just simple addresses in memory.
If your lambdas are simple and don't capture anything, like the one in your example, std::function is overkill. You can just use void(*)() instead and the issue is solved.
Otherwise, if your lambdas do capture stuff, then you need std::function and perhaps some static member variables.
Since you seem to be using only one timer, you could do something like this:
class Timer
{
private:
hw_timer_t* timer = nullptr;
static std::function<void(void)> onTimer;
static void onTimerCaller()
{
onTimer();
}
public:
Timer(uint16_t intervalMs, std::function<void(void)>&& newOnTimer)
{
if (onTimer)
{
// another Timer already exists. Show an error, somehow
}
onTimer = std::move(newOnTimer);
timer = timerBegin(0, 40, true);
timerAttachInterrupt(timer, &onTimerCaller, true);
timerAlarmWrite(timer, intervalMs * 1000, true);
}
void start()
{
timerAlarmEnable(timer);
}
};
The most important changes are1:
Add a onTimerCaller static function (that can be converted to void(*)() and therefore used with timerAttachInterrupt) which calls onTimer;
onTimer is now static, so it can be accessed from onTimerCaller.
Also note that I tried to keep the class as simple as possible. It should also have copy/move constructors/operators and a destructor. Additionally, there's not really much reason to even use a class in this case. A namespace with some functions would be simpler and cleaner.
It is also possible to support multiple timers, but I believe this may be enough for your use-case. Let me know if you'd like to see a version for multiple timers.
1 I also did some minor changes, like moving the std::function into the class to avoid a dangling reference.
I need to assign a callback function with given parameters, so when the event gets triggered and the callback function is called, it calls the function with given parameters. I've looked at multiple websites and I've been trying to find a solution but no luck. Might be that I'm just so dumb, what can I do?
Here's a bit of what I'm trying to do -
void callbackFunction(int someParameter) {
// Do something here
}
master.ButtonL1.pressed(callbackFunction(3));
// The code above doesn't work, just there to show what I'm wanting to do
You can use lambda.
master.ButtonL1.pressed([]{callbackFunction(3);});
In addtion to using a lambda expression, as suggested in the answer by songyuanyao, you can use the following method.
void realCallbackFunction(int someParameter)
{
// DO the real work
}
static int parameter = 0;
void callbackFunction()
{
realCallbackFunction(paramter);
}
...
paramter = 3;
master.ButtonL1.pressed(callbackFunction);
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.
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.
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.
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);
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.
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.
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()
GameObject class .h + .cpp:
typedef std::function<void(GameObject* triggerobject, GameObject* otherobject, TriggerAction action)> PhysicsCallback;
void GameObject::OnTrigger(GameObject* triggerobject, GameObject* otherobject, TriggerAction action)
{
if (m_OnTriggerCallback)
m_OnTriggerCallback(triggerobject, otherobject, action);
}
void GameObject::SetOnTriggerCallBack(PhysicsCallback callback)
{
m_OnTriggerCallback = callback;
}
Other class:
m_pSphere->SetOnTriggerCallBack(*pCbObj);
m_pSphere->OnTrigger(m_pWallLeft, m_pSphere, GameObject::TriggerAction(0));
I figured to use the OnTrigger() function I had to set m_OnTriggerCallback. When I tried to pass corresponding arguments however I got really stuck. It seems almost impossible to initalize PhysicsCallback without getting compiler errors.
I tried:
std::function<void(GameObject* triggerobject, GameObject* otherobject, GameObject::TriggerAction action)> *obj;
*obj = (m_pWallRight, m_pSphere, GameObject::TriggerAction(0));
But no luck. *obj doesn't accept any arguments. These following lines give the same errors:
GameObject::PhysicsCallback *pCbObj; = new GameObject::PhysicsCallback(new std::function<void()>()); //term does not evaluate to a function taking 3 arguments
GameObject::PhysicsCallback *pCbObj = new GameObject::PhysicsCallback((m_pWallRight, m_pSphere, GameObject::TriggerAction(0)));
And this line *pCbObj = GameObject::PhysicsCallback(m_pWallRight, m_pSphere, GameObject::TriggerAction(0));gives this intellisense error:
http://puu.sh/gi29n/95f0f7855b.png
I'm really confused, how to use the SetOnTriggerCallBack function?
Doing
m_pSphere->OnTrigger(m_pWallLeft, m_pSphere, GameObject::TriggerAction(0));
is actually calling GameObject::TriggerAction with 0 as argument. Then, it passes its result.
What is GameObject::TriggerAction? Is it a static method ? It should be because, otherwise, you have either to std::bind it to an object instance or to apply it directly.
With a lambda I was able to create an parameter that was acceptable for the compiler:
GameObject::PhysicsCallback trigger = [=](GameObject* triggerobject, GameObject* otherobject, GameObject::TriggerAction action){};
I'm trying to store a callback in a class. Currently, I do something like this:
struct Callback {
Callback (std::function<void ()> func) : func_ (func){}
void call() const { func(); }
private:
std::function<void ()> func_;
};
As you can see, only a specific type of function (currently no return and no parameters) can be used.
Is there any way I could use such a class like this, where I pass it what to call it with?
void increment (int &n) {
++n;
}
int main() {
int someNum = 5;
Callback callback (increment, someNum); //will call `increment (someNum);`
}
I was thinking to use a parameter pack to store the arguments, and a typename to store the return type, and then making an std::function<ReturnType (Args)> callback_ sort of thing, and calling it with something like callback_ (givenArgs...);. I'm not really knowledgeable enough on templates to do this, however, or even figure out if it's possible.
The real use I'd be getting out of this (at least right now) is for a timer, but perhaps making a small generic_function<> class that wraps an std::function<> would help more. For this example, though, a timer that pauses and unpauses every 2 seconds:
void togglePause (Countdown &c) {
c.togglePause();
}
int main() {
Countdown main (10000); //create countdown of 10s
Countdown delay (2000, togglePause, main); //this one calls func when expired
for (; !main.expired();) { //go while unpaused time < 10s
delay.wait().reset(); //wait 2s, call callback, reset back to 2s
}
}
Of course this can be applied to other concepts as well, but I'm not sure how to go about attaining this syntax in the first place. I can build two different forms in case the return type is void just fine from an unrelated previous question, but storing a function with any number and types of arguments confuses me. If it's possible, how can I use syntax like this? If not, how close would the syntax be?
I think you just want to use std::bind to convert your function with an argument into a function taking no arguments:
int main() {
int someNum = 5;
std::function<void (void)> boundFunc = std::bind(increment, std::ref(someNum));
Callback callback (boundFunc); //will call `increment (someNum);`
}
Note that you need the std::ref to ensure that someNum is passed by reference and that you need to make sure that someNum stays in scope longer than the callback.