C++ pass function pointer with parameter to function - c++

I think I have misunderstood how function pointers work. In this example:
class Helper
{
public:
typedef void (*SIMPLECALLBK)(const char*);
Helper(){};
void NotifyHelperbk(SIMPLECALLBK pCbk)
{ m_pSimpleCbk = pSbk; }
private:
SIMPLECALLBK m_pSimpleCbk;
}
// where i call the func
class Main
{
public:
Main(){};
private:
Helper helper
void SessionHelper(const char* msg);
}
Main.cpp
void Main::SessionHelper(const char* msg)
{
....
}
helper.NotifyHelperbk(&Main::SessionHelper);
I get the following error:
error C2664: 'Main::NotifyHelperbk' : cannot convert parameter 1 from 'void (__thiscall Main::* )(const char *)' to 'Helper::SIMPLECALLBK'
1> There is no context in which this conversion is possible
What am I missing here?

Main::SessionHelper is a non static method. So add static to it to be able to use it as function pointer. Or use member method pointer (you will need a instance to call it).

if you use c++11 you can use std::bind
class Helper
{
public:
void NotifyHelperbk(std::function<void(char*)> func){
/* Do your stuff */
func("your char* here");
}
And your main :
Main.cpp
Main m;
helper.NotifyHelperbk(std::bind(&Main::SessionHelper, m, std::placeholder_1));

Related

C++ - How to bind a callback to a class method without being static?

I have my class:
class Foo
{
public:
(...)
private:
void mycallback(void* buff, wifi_promiscuous_pkt_type_t type);
void registerMyCallback();
};
The mycallback is the callback.
I want to use a method esp_wifi_set_promiscuous_rx_cb to register the mycallback so that when a WiFi packet is detected, this callback method will be executed.
The esp_wifi_set_promiscuous_rx_cb signature is:
esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);
Where the wifi_promiscuous_cb_t definition is:
typedef void (* wifi_promiscuous_cb_t)(void *buf, wifi_promiscuous_pkt_type_t type);
I want to use the mycallback method inside my class, therefore I simply can't use like this:
void Foo::registerMyCallback()
{
esp_wifi_set_promiscuous_rx_cb(&mycallback);
}
I know that I could use something similar if I would just make my method as static.
Is there anyway that I bind mycallback to esp_wifi_set_promiscuous_rx_cb without making the callback static?
I have tried the following:
esp_wifi_set_promiscuous_rx_cb(std::bind(&Foo::mycallback, this, std::placeholders::_1, std::placeholders::_2));
But I am still having the following error:
cannot convert 'std::_Bind_helper<false, void (Foo::Foo::*)(void*, wifi_promiscuous_pkt_type_t),
Foo::Foo*, const std::_Placeholder<1>&, const std::_Placeholder<2>&>::type
to
'wifi_promiscuous_cb_t {aka void (*)(void*, wifi_promiscuous_pkt_type_t)}' for argument '1'
Th library you are using is C package.
Thus the only guaranteed way pass a valid function is to pass a C function with C linkage. This function can then call the method on your object.
If you want the callback method to be non static you need to store a pointer (ore reference) to the callback object somewhere that your callback function can find it. (in most C callback functions you can provide a void* object that is passed to your callback, but this interface does not seem to allow this so you will have to save the value yourself).
Foo* myCBObject = nullptr;
extern "C" void myCB(void *buf, wifi_promiscuous_pkt_type_t type)
{
try
{
myCBObject->mycallback(buff, type);
}
catch(...) {} // Don't allow exceptions to cross C linkage
}
...
// Your code.
void Foo::registerMyCallback()
{
myCBObject = this;
esp_wifi_set_promiscuous_rx_cb(myCB);
}
Note: You should NOT be registering static member functions with a C library. If this works it is only by chance. There is no guarantee that a static function has the same calling convention of a C function (they usually do but that is not guaranteed).
After some research, I hope I found the solution. The trick is to bind member function first and then obtain the function pointer from the std::function. Notice the usage of my_wifi_promiscuous_cb_t and std::function::target<>().
#include <iostream>
#include <functional>
using namespace std::placeholders;
// using fake definitions
extern "C"
{
enum wifi_promiscuous_pkt_type_t {};
typedef int32_t esp_err_t;
typedef void (*wifi_promiscuous_cb_t)(void* buf, wifi_promiscuous_pkt_type_t type);
typedef void my_wifi_promiscuous_cb_t(void* buf, wifi_promiscuous_pkt_type_t type);
esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb)
{
return 0;
}
}
class Class
{
public:
void mycallback(void* buff, wifi_promiscuous_pkt_type_t type) {}
void registerMyCallback() {
std::function<void(void*, wifi_promiscuous_pkt_type_t)> fun2 = std::bind(&Class::mycallback, this, _1, _2);
esp_wifi_set_promiscuous_rx_cb(fun2.target<my_wifi_promiscuous_cb_t>());
}
};
int main()
{
Class c;
c.registerMyCallback();
}

C++ template overload call

I am trying to implement an execution pattern which takes any function and executes it with its own conditions/preparations. Regardless of this being a useful thing to do, it just doesn't work. It seems i can't access the template overload of the "Execute"-function (called in "main").
Specifically: Why can't i call the overloaded template function of Execute?
This is the full program:
#include "stdafx.h"
#include <functional>
class TransparentFunctionWrapper
{
public:
virtual void Execute(std::function<void()> executeFunction) = 0;
template<class C>
C Execute(std::function<C(void)> executeFunction) // template-overload of the abstract function which will implicitly call it
{
C ret;
Execute( // calls the abstract function with a lambda function as parameter
[ret, executeFunction](void) -> C // lambda declaraction
{ //
ret = executeFunction; // lambda body
}); //
return ret;
}
};
class ExampleExecutor : public TransparentFunctionWrapper
{
public:
virtual void Execute(std::function<void()> executeFunction)
{
printf("executed before.");
executeFunction();
printf("executed after.");
}
};
void DoStuff() {}
int ReturnStuff() { return -5; }
int main()
{
ExampleExecutor executor;
executor.Execute(DoStuff);
int i = executor.Execute<int>(ReturnStuff); // Why does this not work? ERROR: "type name is not allowed"
getchar();
return 0;
}
Note: Visual Studio marks
Execute<int>(ReturnStuff) // "int" is marked as Error: type name is not allowed
The compilation puts out the error
"type 'int' unexpected"
Thanks to everyone willing to help!
ExampleExecutor::Execute is not overriding TransparentFunctionWrapper::Execute, and it is hiding it in the executor.Execute<int> call.
You must explicitly call TransparentFunctionWrapper::Execute, as it is hidden by ExampleExecutor::Execute. Here's a possible way of doing that:
int i = executor.TransparentFunctionWrapper::Execute<int>(ReturnStuff);
live example on coliru

c++ pointer to a function as argument

I have a C++ API with a cThread class, and this method to create a thread:
void cThread::start(void(*a_function)(void), CThreadPriority a_level);
I've done a class and a init() method to launch a thread and an updateHaptics() method to be executed by the thread:
void EntryClass::init()
{
typedef void (EntryClass::*method)();
method p;
p = &EntryClass::updateHaptics;
// create a thread which starts the main haptics rendering loop
cThread* hapticsThread = new cThread();
hapticsThread->start(p, CTHREAD_PRIORITY_HAPTICS);
}
void EntryClass::updateHaptics(void)
{
// ...
}
My problem is to pass the updateHaptics() method as an argument to the cThread::start() method.
I've got this error:
1>EntryClass.cpp(55): error C2664: 'void chai3d::cThread::start(void (__cdecl *)(void *),const chai3d::CThreadPriority,void *)' : impossible de convertir l'argument 1 de 'method' en 'void (__cdecl *)(void)'
REM: I'm under Windows 8/Visual Studio
The signature you indicated
void(*a_function)(void)
is for a function, not for a class method. A static method will work too
Note the difference with the typedef you used:
void (EntryClass::*method)();
The definition could be:
class EntryClass {
public:
void init();
static void updateHaptics(); // <--- NOTE the static
};
and your implementation
void EntryClass::init()
{
typedef void (*method)(); // <---- NOTE THIS CHANGE
method p;
p = &EntryClass::updateHaptics;
// create a thread which starts the main haptics rendering loop
cThread* hapticsThread = new cThread();
hapticsThread->start(p, CTHREAD_PRIORITY_HAPTICS);
}
void EntryClass::updateHaptics(void)
{
// ...
}
As I know, we can use only static function as a thread proc. Yes we can pass class static function also.

error: cannot convert 'void (CApp::*)()' to 'void (*)()' for argument '1' to 'void Mix_HookMusicFinished(void (*)())'

I'm trying to create a C++ application using SDL and SDL_Mixer for audio, and am trying to follow this tutorial. However, using SDL_Mixer's Mix_HookMusicFinished() isn't working, giving the error: argument of type 'void (CApp::)()' does not match 'void (*)()'
I've researched this error, and it seems the problem is that cleanMusic is a member function of CApp. I can't tell how to solve the problem, however, since most problems similar to this one are centered around pthread_create(). My cleanMusic() function needs to be able to access music_ which is a private variable of CApp. How can I resolve the error?
Here is the code for CApp.h, CApp::handleKeyEvents(), and CApp::cleanMusic(). Let me know if you need to see something else.
CApp.h
#ifndef CAPP_H
#define CAPP_H
#include <SDL.h>
#include <SDL_mixer.h>
#include <gl\gl.h>
#include <gl\glu.h>
class CApp {
private:
bool isRunning_;
private:
void cleanMusic();
private:
SDL_Surface *surfDisplay_;
Mix_Music *music_;
bool isRotating_;
GLfloat rQuad_;
public:
CApp();
int run();
public:
bool initialize();
void handleEvents(SDL_Event *event);
void loopData();
void render();
void clean();
public:
void handleKeyEvents(SDL_KeyboardEvent *key);
};
#endif // CAPP_H
CApp::handleKeyEvents()
#include "CApp.h"
void CApp::handleKeyEvents(SDL_KeyboardEvent *key) {
switch(key->keysym.sym) {
case SDLK_m:
if (key->state == SDL_PRESSED) {
if(music_ == NULL) {
music_ = Mix_LoadMUS("resources\\audio\\boop.wav");
Mix_PlayMusic(music_, 0);
Mix_HookMusicFinished(cleanMusic);
isRotating_ = true;
} else {
Mix_HaltMusic();
cleanMusic();
isRotating_ = false;
}
}
break;
default:
break;
}
}
CApp::cleanMusic()
#include "CApp.h"
void CApp::cleanMusic() {
Mix_FreeMusic(music_);
music_ = NULL;
}
Two changes. cleanMusic needs to be static.
static void cleanMusic();
Second, you register the hook with:
Mix_HookMusicFinished(&CApp::cleanMusic);
Since your method is now static, music_ needs to be static as well.
static Mix_Music *music_;
This means that there will only be one instance of this variable shared between all instantiations of CApp. Since I haven't seen all of your code, I can't tell if this is an issue.
void cleanMusic(); is what is known as a member function. A member function is very different from a normal function. The reason your compiler complains is because Mix_HookMusicFinished expects a normal function pointer of type void (*)(), but you are trying to pass a member function pointer of type void (CApp::*)(). These types are incompatible.
The simplest solution is just to make cleanMusic a normal function and Mix_Music *music; a global:
Mix_Music *music;
void cleanMusic() {
Mix_FreeMusic(music);
music = NULL;
}
Another way is to make them both static members:
static void cleanMusic();
static Mix_Music *music_;

calling method using CCCallFuncN or something

Code:
prog.h
public:
virtual bool init();
static cocos2d::CCScene* scene();
CREATE_FUNC(ProgScene);
void spriteMoveFinished(CCNode* sender);
void endCallback(CCObject* pSender);
void endCallbackWork(CCNode* pSender);
prog.cpp
void ProgScene::spriteMoveFinished(CCNode* sender)
{
CCMessageBox("Sprite Move Finished","Sprite Move Finished");
this->runAction(CCCallFuncN::actionWithTarget( this, callfuncN_selector(ProgScene::endCallbackWork))); // WORK
// this->runAction(CCCallFuncN::actionWithTarget( this, callfuncN_selector(ProgScene::endCallback))); // NOT WORK
}
void ProgScene::endCallback(CCObject* pSender)
{
...
CCMessageBox("From endCallback","From endCallback");
}
void ProgScene::endCallbackWork(CCNode* sender)
{
...
CCMessageBox("from endCallbackWork","from endCallbackWork");
}
I'm a beginner in cpp, please help me.
How can i call method endCallback from method actionWithTarget ?
When i use
this->runAction(CCCallFuncN::actionWithTarget( this, callfuncN_selector(ProgScene::endCallback)));
it returns:
error C2440: 'type cast' : cannot convert from 'void (__thiscall ProgScene::* )(cocos2d::CCObject *)' to 'cocos2d::SEL_CallFuncN'
1> Pointers to members have different representations; cannot cast between them
endCallbackWork is good working with
this->runAction(CCCallFuncN::actionWithTarget( this, callfuncN_selector(ProgScene::endCallbackWork)));
Maybe I can use another way than the following ?
this->runAction(CCCallFuncN::actionWithTarget( this, callfuncN_selector(ProgScene::endCallback)));