I would like someone to shed some light this code snippet, which confuses me.
//-------------------------------------------------------------------------------
// 3.5 Example B: Callback to member function using a global variable
// Task: The function 'DoItB' does something that implies a callback to
// the member function 'Display'. Therefore the wrapper-function
// 'Wrapper_To_Call_Display is used.
#include <iostream.h> // due to: cout
void* pt2Object; // global variable which points to an arbitrary object
class TClassB
{
public:
void Display(const char* text) { cout << text << endl; };
static void Wrapper_To_Call_Display(char* text);
/* more of TClassB */
};
// static wrapper-function to be able to callback the member function Display()
void TClassB::Wrapper_To_Call_Display(char* string)
{
// explicitly cast global variable <pt2Object> to a pointer to TClassB
// warning: <pt2Object> MUST point to an appropriate object!
TClassB* mySelf = (TClassB*) pt2Object;
// call member
mySelf->Display(string);
}
// function does something that implies a callback
// note: of course this function can also be a member function
void DoItB(void (*pt2Function)(char* text))
{
/* do something */
pt2Function("hi, i'm calling back using a global ;-)"); // make callback
}
// execute example code
void Callback_Using_Global()
{
// 1. instantiate object of TClassB
TClassB objB;
// 2. assign global variable which is used in the static wrapper function
// important: never forget to do this!!
pt2Object = (void*) &objB;
// 3. call 'DoItB' for <objB>
DoItB(TClassB::Wrapper_To_Call_Display);
}
Question 1: Regarding this function call:
DoItB(TClassB::Wrapper_To_Call_Display)
Why does Wrapper_To_Call_Display not take any arguments, although it is supposed to take a char* argument according to its declaration?
Question 2: DoItB is declared as
void DoItB(void (*pt2Function)(char* text))
What I’ve understood so far is that DoItB takes a function pointer as argument, but why does the function call DoItB(TClassB::Wrapper_To_Call_Display) take TClassB::Wrapper_To_Call_Display as argument even tough it’s not a pointer?
Thanx in advance
Source of code snippet: http://www.newty.de/fpt/callback.html
In C/C++ when a function name is used with no parameters - that is no parenthesis - it is a pointer to a function. So TClassB::Wrapper_To_Call_Display is a pointer to the address in memory where the code for the function is implemented.
Since TClassB::Wrapper_To_Call_Display is a pointer to a void function that takes a single char* it's time is void (*)(char* test) so it matches the type required by DoItB.
Related
I'm having a small problem which I can't wrap my head around.
I have a function that looks like this:
template <typename T>
std::unique_ptr<Environment>& CreateEnvironment(sf::Vector2f& _position, bool _addToStatic = false);
This is my function pointer typedef
typedef std::unique_ptr<Environment>& (WorldEditor::*CreateEnvironmentPtr)(sf::Vector2f&, bool);
std::map<std::string,CreateEnvironmentPtr> listEnv;
And I'm trying to simply do this:
listEnv["test"] = &CreateEnvironment<Coin>(sf::Vector2f(200,200), false);
And i get the following error:
error C2440: '=' : cannot convert from 'std::unique_ptr<_Ty> *' to
'std::unique_ptr<_Ty> &(__thiscall WorldEditor::* )(sf::Vector2f
&,bool)'
I understand what the error is saying, but I don't know how to solve it. Also why does it even care about the return type when I'm pointing to the address of the function?
Best regards
nilo
problems such as these are often much better solved with std::function
std::map<std::string, std::function<void()> listEnv;
listEnv.emplace("test", [] {
CreateEnvironment<Coin>(sf::Vector2f(200,200), false);
});
to call:
listEnv.at("test")->second();
Based on your post I am not sure if you are attempting to create the member function pointer and map inside the CreateEnvironment class or outside of it, so I'll solve what I think is the more difficult problem of pointer to a separate object's member function.
I simplified your classes like so:
Environment
struct Environment
{
int i = 1;
};
Coin
struct Coin
{
int k = 0;
};
WorldEditor
struct WorldEditor
{
template <typename T>
std::unique_ptr<Environment> CreateEnvironment(int& _j, bool _addToStatic = false)
{
return std::make_unique<Environment>();
}
};
Solution: Map an object's member fn pointer, and then call it later
(I will be using C++11/14 syntax in my answer)
//declare a pointer to member function in WorldEditor
using CreateEnvironmentPtr = std::unique_ptr<Environment> (WorldEditor::*)(int&, bool);
//declare an object of type WorldEditor, because member function pointers need a "this" pointer
WorldEditor myWorldEditor;
int myInt = 42;
//map a string to the CreateEnvironment<Coin> function
std::map<std::string, CreateEnvironmentPtr> listEnv;
listEnv["test"] = &WorldEditor::CreateEnvironment<Coin>;
// call the member function pointer using the instance I created, as well as
// the mapped function
(myWorldEditor.*listEnv["test"])(myInt, false);
// (printing member value to cout to show it worked)
std::cout << (myWorldEditor.*listEnv["test"])(myInt, false)->i << std::endl; // prints 1
Live Demo
Solution 2: use std::bind and std::function
Perhaps we already know the parameters to the member function call at the time we create the entry for map. Using std::bind with a std::function will help us achieve that (Similar to Richard Hodges' solution):
// now our "function pointer" is really just a std::function that takes no arguments
using CreateEnvironmentPtr = std::function<std::unique_ptr<Environment>(void)>;
//declare an object of type WorldEditor, because member function pointers need a "this" pointer
WorldEditor myWorldEditor;
int myInt = 42;
//map a string to that function pointer
//ensure it gets called with the right args
// by using std::bind (which will also make the arg list appear the be void at call time)
// note that std::bind needs an instance of the class immediately after
// listing the function it should be binding
// only afterwards will we then pass the int& and bool
std::map<std::string, CreateEnvironmentPtr> listEnv;
listEnv["test"] = std::bind(&WorldEditor::CreateEnvironment<Coin>, &myWorldEditor, myInt, false);
// the mapped function
listEnv["test"]()->i;
// (printing resulting unique_ptr<Environment>'s member to cout to show it worked)
std::cout << listEnv["test"]()->i << std::endl; // prints 1
Live Demo 2
I want to bind a member function to a std::function<void(void)>. I heard that member functions take one extra parameter which is the instance pointer. Therefore I call std::bind(&Class::Function, this, parameter) but when I execute the function object, it throws a runtime error.
Unhandled exception at at 0x748D4B32 in Application.exe: Microsoft C++
exception: std::bad_function_call at memory location 0x0114F4E8.
The parameter is a pointer to one of my own structs. How am I doing wrong? What additional information do you need?
Update: Here is my code.
class ModuleRenderer
{
struct Pass{ std::function<void()> Function; /* many more members... */ };
std::vector<std::pair<std::string, Pass>> passes;
enum Drawfunc{ FORMS, SKY, LIGHTS, QUAD, SCREEN };
void AddPass(std::string Name, Drawfunc Function)
{
Pass pass;
// set some of the members
// ...
passes.push_back(std::make_pair(Name, pass));
Pass *pointer = &(passes.back().second);
switch (Function)
{
case FORMS:
pointer->Function = std::bind(&ModuleRenderer::DrawForms, this, pointer);
break;
// analogeously for the other cases
// ...
}
}
void DrawForms(Pass *pass)
{
// ...
}
// is called consecutively after adding all passes
void Update()
{
for(auto i : passes)
// some initializing based on members of pass
i.Function();
}
};
A couple of different issues have been pointed out in the comments above. To resolve these, try making the following changes to your code:
struct Pass{ std::function<void(Pass *)> Function; /* ... */ };
// ...
case FORMS:
pointer->Function =
std::bind(&ModuleRenderer::DrawForms, this, std::placeholders::_1);
break;
Do not bind the Pass * to the function call just yet, because, as #molbdnilo points out, that pointer will become invalid when you call AddPass() multiple times and the vector is resized.
Since the std::function now takes a Pass *, you need to supply the correct pointer when you invoke it.
void Update()
{
for(auto& i : passes) { // <-- take a reference, don't copy
// some initializing based on members of pass
i.Function( &i ); // pass Pass * to the function
}
passes.push_back(std::make_pair(Name, pass));
Pass *pointer = &(passes.back().second);
That pointer will become invalid when you later push_back and the vector grows.
You could avoid pointers altogether and pass the index of the corresponding object instead of a pointer.
pointer->Function = std::bind(&ModuleRenderer::DrawForms, this, passes.size() - 1);
// ...
void DrawForms(size_t i)
{
Pass& pass = passes[i].second;
// Handle as before...
}
This question already has answers here:
pthread function from a class
(9 answers)
Closed 9 years ago.
I have a class named qwerty and a function called compute_ans inside it which takes a void pointer and returns a void pointer. Now when I try to compile, the following statement throws an error
pthread_create (thread_a, NULL, compute_ans, (void*) struct_left);
The definition of the function is void* compute_ans (void* struct_input)
The error is
cannot convert ‘qwerty::compute_ans’ from type ‘void* (qwerty::)(void*)’ to type ‘void* ()(void)’*
You cannot convert a pointer to a non-static member function to a pointer to function, C++ does not allow it. The reason is that member functions take an implicit this pointer as a parameter. Essentially this changes the signature of your function to be something like void* compute_ans(qwerty*, void*). In order to pass the function to pthread_create you need to make the member function static.
class qwerty
{
public:
// ... other member functions and variables ...
// thread start function
static void* compute_ans(void*);
};
If you cannot make this a static member function you will need to pass a pointer to a qwerty object to the thread start function. Looking at the code in your question you also need to pass additional data to the thread function. To do this you can use an additional data structure that contains all the necessary data and pass a pointer to that instead.
class qwerty; // forward declaration
// Structure passed to pthread_create and our helper function
struct thread_data
{
qwerty* qptr; // pointer to qwerty object
void* data; // pointer to other data. change void to your data type.
};
class qwerty
{
public:
// thread start function
static void* start_compute_ans(void* param)
{
// get a pointer to the thread data
thread_data* tdata = static_cast<thread_data*>(param);
// Call the real compute_ans
tdata->qptr->compute_ans(tdata->data);
// Delete the data (use an appropriate smart pointer if possible)
delete tdata;
return NULL;
}
// the real
void compute_ans(void*)
{
// do stuff here
}
};
// Create our thread startup data
thread_data* tdata = new thread_data();
tdata->qptr = qwerty_pointer;
tdata->data = struct_left;
// start the thread data
pthread_create (thread_a, NULL, &qwerty::start_compute_ans, tdata);
You can find the answer here.
You should use static functions to pass to pthread.
class qwerty
{
public:
void compute_ans(void)
{
std::cout << "Compute result!" << std::endl;
return
}
static void hello_helper(void *context)
{
return ((qwerty *)context)->compute_answer();
}
};
...
qwerty c;
pthread_t t;
pthread_create(&t, NULL, &qwerty::hello_helper, &c);
I will like to know, how to make a function where I define a function. And then I can call the defined function. Let me try with a example.
void funcToCall() {
std::cout<<"Hello World"<<std::endl;
}
void setFuncToCall(void func) {
//Define some variable with func
}
void testFuncCall() {
//Call function that has been defined in the setFuncToCall
}
setFuncToCall(funcToCall()); //Set function to call
testFuncCall(); //Call the function that has been defined
I Hope that you understand what I am trying to do here. But I don't know how to bring It down to the right code :-)
You need a function pointer. It's easier to work with function pointers if you typedef them first.
typedef void (*FuncToCallType)();
FuncToCallType globalFunction; // a variable that points to a function
void setFuncToCall(FuncToCallType func) {
globalFunction = func;
}
void testFuncCall() {
globalFunction();
}
setFuncToCall( funcToCall ); //Set function to call,NOTE: no parentheses - just the name
testFuncCall(); //Call the function that has been defined
As other answers have suggested you can use objects like functions, too. But this requires operator overloading (even if it remains hidden from you) and is typically used with templates.
It gives more flexibility (you can set some state to the object before passing it to the function and the object's operator() can use that state) but in your case function pointers may be just as good.
What you want to use is a callback, and is has been answered her : Callback functions in c++
I would advise you to use std::tr1::function ( generalized callback )
C syntax for function pointers is a bit weird, but here we go:
// this is a global variable to hold a function pointer of type: void (*)(void)
static void (*funcp)(void);
// you can typedef it like this:
//typedef void (*func_t)(void);
// - now `func_t` is a type of a pointer to a function void -> void
// here `func` is the name of the argument of type `func_t`
void setFuncToCall(void (*func)(void)) {
// or just: void setFuncToCall(func_t func) {
//Define some variable with func
...
funcp = func;
}
void testFuncCall(void) {
//Call function that has been defined in the setFuncToCall
funcp();
}
setFuncToCall(funcToCall); // without () !
testFuncCall();
i'm trying to create a new thread with a class "CameraManager" but i have the following error:
cannot convert '*void(CameraManager:: * )(void*) to void*( * )(void*) in pthread_create function
i defined in the cameramanager.h file:
public:
void *dequeueLoop(void *ptr);
and in the cameramanager.cpp
void CameraManager::startDequeuing(){
dequeuing = true;
dequeueThreadId = pthread_create(&dequeueThread, NULL, &CameraManager::dequeueLoop, NULL);
}
void *CameraManager::dequeueLoop(void *ptr){
while(dequeuing){
highSpeedCamera->dequeue();
highSpeedCamera->enqueue();
}
I don't want to declare dequeueLoop as a static function i also tried to declare dequeueLoop as a class friend function in the following way but then it doesn't have scope on class variables 'highSpeedCamera' and 'dequeuing' and the compiler also tell me that 'dequeueLoop' was not declared in this scope
to make dequeueLoop a friend function i did:
cameramanager.h
public:
friend void *dequeueLoop(void *ptr);
cameramanager.cpp
void CameraManager::startDequeuing(){
dequeuing = true;
dequeueThreadId = pthread_create(&dequeueThread, NULL, &CameraManager::dequeueLoop, NULL);
}
void *dequeueLoop(void *ptr){
while(dequeuing){
highSpeedCamera->dequeue();
highSpeedCamera->enqueue();
}
}
Where i'm doing wrong?
I don't want to declare dequeueLoop as a static function
If you want to use pthreads, then you'll need a static or non-member function for the entry point. You can pass a pointer to your object to this function, using it as a trampoline into the non-static member function:
static void * dequeueEntry(void * self) {
return static_cast<CameraManager*>(self)->dequeueLoop();
}
dequeueThreadId = pthread_create(
&dequeueThread, NULL,
&CameraManager::dequeueEntry, // <-- pointer to trampoline function
this); // <-- pointer to object for member function
Alternatively, if you have a modern compiler, you could use the standard thread library instead:
std::thread thread(&CameraManager::dequeLoop, this);
If you want the function to be a member of the class, it must be static. It's because the thread function will be called directly and will not have a valid this pointer. This can be solved by having a wrapper function, that gets passed the actual object and then calls the proper member function:
void *dequeueLoopWrapper(void *p)
{
CameraManager *cameraManager = static_cast<CameraManager*>(p);
camereraManager->dequeueLoop();
return nullptr;
}
// ...
void CameraManager::startDequeuing()
{
dequeuing = true;
dequeueThreadId = pthread_create(&dequeueThread, NULL, dequeueLoopWrapper, this);
}
However, I would recommend you start using the threading support in the new standard library:
void CameraManager::startDequeuing()
{
dequeuing = true;
myThread = std::thread(&CameraManager::dequeueLoop, this);
}
You can't use a pointer to member function as a function pointer unless it's static. You'll have to make dequeueLoop a free function, or write a free function as a wrapper to it.
To access the class members in a free function, you should have the function pass it's this pointer as the final argument of pthread_create. Then have the free function cast it's argument to a pointer to the class.