In cocos2d-x, the following piece of code is supposed to run the callback function after a delay. What do I need to do to fix the error?
bool LoadingLevelScreen::initialise() {
// set up the time delay
CCDelayTime *delayAction = CCDelayTime::actionWithDuration(0.5f);
// perform the selector call
CCCallFunc *callSelectorAction = CCCallFunc::actionWithTarget(
this, callfunc_selector( LoadingLevelScreen::menuCallbackStart ) );
// run the action
this->runAction( CCSequence::actions(
delayAction, callSelectorAction, NULL ) );
}
void LoadingLevelScreen::menuCallbackStart(CCObject * pSender)
{
}
Compiler Error:
error C2440: 'type cast' :
cannot convert from 'void (__thiscall LoadingLevelScreen::* )(cocos2d::CCObject *)'
to 'cocos2d::SEL_CallFunc'
Pointers to members have different representations; cannot cast between them
Either remove the CCObject* parameter in menuCallbackStart() method (because CCCallFunc::actionWithTarget() expects a method with no arguments), or change CCCallFunc to CCCallFuncO which expects a method with a CCObject* as argument, like so:
CCCallFuncO * callSelectorAction =
CCCallFuncO::create(this, &LoadingLevelScreen::menuCallbackStart, myObject);
where myObject is a CCObject * that will be passed to your method as the argument.
Note that callfunc_selector() is just a macro that typecasts your method to SEL_CallFunc:
#define callfunc_selector(MYSELECTOR) (SEL_CallFunc)(& (MYSELECTOR))
BTW ::actionWithTarget() is being deprecated, so use ::create() instead.
void LoadingLevelScreen::menuCallbackStart(CCObject * pSender)
{
}
should be
void LoadingLevelScreen::menuCallbackStart()
{
}
callfunc_selector is different with menu_selector, you don't need the CCObject* to pass in as a variable
if you do need to pass argument, please use callFuncND
this->runAction(Sequence::create(CallFunc::create(std::bind(&CNm::MNm, this)),NULL));
this->runAction(Sequence::create(CallFunc::create(std::bind(&ClassName::MethodName, this)),NULL));
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've got this header:
class jmmvAsync
{
public:
static void run(LPCTSTR msg);
};
and this .cpp
void jmmvAsync::run(LPCTSTR msg){
MessageBox(NULL, msg, NULL, NULL);
}
And I'm calling a this function:
LPTCSTR file = "file";
thread t(jmmvAsync::run(file), 0);
thread function has this structure:
thread::thread(void (*aFunction)(void *), void * aArg)
Why am I getting wrong types when calling to "thread"?
Error code:
COMPILE : error C2664: 'tthread::thread::thread(void (__cdecl *)(void *),void *)' : cannot make conversion of parameter 1 with type 'void' to 'void (__cdecl *)(void *)'
thread function expects paramater 1 to be void (__cdecl *)(void *) and my function is just void. I don't know how to make my function named run the same type as requested.
As it was mentioned in comments (but maybe in an unclear fashion), your code tries to pass the return value of the function, instead of the pointer to the function.
This constructor
thread::thread(void (*aFunction)(void *), void * aArg)
expects a pointer to a function as the first argument.
This
jmmvAsync::run(file)
invokes the function and its result is the function's return value (which is void). This is absolutely not what you want. You want an address of the function:
&jmmvAsync::run
Send it to your constructor this way:
LPTCSTR file = "file";
thread t(&jmmvAsync::run, file);
Note: the second parameter is the file, not 0. This is a common pattern in C: you pass the address of the function and its parameter, which is of type void*, and the library code promises to call that function later, passing the parameter to it.
BTW as Aaron McDaid mentions, the type of jmmvAsync::run must be exactly what your constructor requests. That is, it must be declared to receive a parameter of type void* (not LPTCSTR), and be a static member function (which it is, judging by your code). Since you are using names like LPTCSTR, you probably only want your code to run on Windows, so you don't need to worry about the distinction between void* and LPTCSTR.
If in doubt, make a wrapper:
void wrapper_jmmvAsync_run(void* par)
{
jmmvAsync::run(static_cast<LPTCSTR>(file));
}
...
LPTCSTR file = "file";
thread t(&wrapper_jmmvAsync_run, file);
I'm tring to assign OnChange function to another function like:
XComp->OnChange = SycnroChange(prgManVoltageSet_SB->Address);
but compiler gives that error: "Not allowed type."
What should I do? Cant i assign like this?
IIRC you can make assignments like that in the form ->onChange = xyz ; where xyz is another function (or member function) with proper signature. You can't bind arguments and things like that.
So you should change SynchroChange signature first (most event handlers require just a generic TObject *Sender) and then inside that function look for the prgManVoltageSet (unless can be casted from the parameter 'Sender', but I have not enough context for this)
From what you have said, I have knew your intention is that you wanted to execute SycnroChange(prgManVoltageSet_SB->Address) when XComp changed.
So I think you can use a callback function with boost::signal2::signal and boost::bind, such as boost::bind(&SycnroChange, this, _1).
When XComp changed, you could call the callback(prgManVoltageSet_SB->Address) to trigger and get an int.I hope these can help you.
You are calling SycnroChange() and assigning its return value to OnChange. The OnChange event expects a pointer to an object method that conforms to the signature of TNotifyEvent:
typedef void __fastcall (__closure *TNotifyEvent)(System::TObject* Sender);
SycnroChange() has a return value of void instead. Thus the error.
For what you are attempting, you will have to use a separate event handler method that internally calls SycnroChange():
__fastcall TGenerator::TGenerator(TComponent *Owner)
: TForm(Owner)
{
...
// FYI, you can assign this at design-time instead of in code...
XComp->OnChange = &XComChanged;
...
}
void __fastcall TGenerator::XComChanged(TObject *Sender)
{
SycnroChange(prgManVoltageSet_SB->Address);
}
I have to create new thread and send parameters to the threaded function, can't make it work though.
I was working according to this reference: http://msdn.microsoft.com/en-us/library/system.threading.parameterizedthreadstart.aspx
Here is the thread creation (with the errors in the comments):
System::Threading::Thread^ T = gcnew System::Threading::Thread(gcnew System::Threading::ParameterizedThreadStart(this, &Server::ClientHandler)); // ERROR: 'void Server::ClientHandler(System::Object ^,System::Object ^)' : the specified function does not match the delegate type 'void (System::Object ^)'
T->Start(ClientSocket); // ERROR: 'System::Threading::Thread::Start' : no overloaded function takes 2 arguments
Here is ClientHandler decleration:
void Server::ClientHandler(Object^ data, Object^ data1);
I tried it with only one parameter, and I had only the second error.
P.S, in ClientHandler function I have to convert the Object^ parameters to SOCKET* and SOCKADDR_IN*, how it can be done?
My try:
SOCKET* _Sock = (SOCKET*)data;
SOCKADDR_IN* _ADDR = (SOCKADDR_IN*)data1;
I'm using visual studio 2012.
Pretty sure that declaration for Server::ClientHandler is incorrect.
Should be:
void Server::ClientHandler(Object^ data)
{
//Do stuff with data here..
}
System::Threading::Thread^ T = gcnew System::Threading::Thread(gcnew System::Threading::ParameterizedThreadStart(this, &Server::ClientHandler));
T->Start("Pass Your Data Here");
I'm new on C++ and I'm trying to make some testing with C++ and SDL and in SDL we have a function:
SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param);
which I can pass a callback for the timer created.
But apparently it converts my instance this to *void so I can't retrieve it again on the update method which is static, and it's interesting but the the SDL_AddTime doesn't work on a non static callback function.
Well, so my problem is that when trying to call the public method render through the void* param argument It complains about not being a pointer-to-object-type...
Is there any way I can get the Character instance again inside the update method since I don't have control over the SDL_AddTime function and I have to pass the required parameters?
Thanks
#include "Character.h"
Character::Character(void)
{
timer = SDL_AddTimer(33, update, this);
this->render(); // is called without problem
}
//static method
Uint32 Character::update(Uint32 interval,void* param)
{
param->render(); // yields: 'void*' is not a pointer-to-object type;
SDL_Event event;
event.type = SDL_USEREVENT;
event.user.code = 1020;
event.user.data1 = param;
SDL_PushEvent(&event);
return interval;
}
void Character::render(void)
{
printf("rendering character \n");
}
You don't need a reinterpret_cast - a static_cast should be OK:
Character * cp = static_cast <Character *>( param );
You should avoid reinterpret_cast - it is almost always implementation specific, and may hide problems - just like old-style C casts.
Cast your param pointer to a Character:
Character * charPtr = reinterpret_cast<Character *>(param);
charPtr->render();
The reason is that C++ is a strong typed language. To change one type to another, you need to cast it first:
Uint32 Character::update(Uint32 interval, void* param)
{
reinterpret_cast<Character* >(param)->render();
/* ... */
}
Just for reference, if you were to call a lot of stuff in a function, to save all the nasty reinterpret_cast stuff everywhere you can do
Character * myCharacter = reinterpret_cast<Character* >(param);
Which then lets you do 'myCharacter->render();' or whathaveyou...