I hope to use map library to call a function by a string with the function name, I've tested the following example and everything are working well.
#include <string>
#include <iostream>
using namespace std;
typedef void (*pFunc)();
map<string, pFunc> strFuncMap;
void func1()
{
printf("this is func1!\n");
}
void buildMap()
{
strFuncMap["func1"] = &func1;//
}
void callFunc(const std::string& str)
{
(*strFuncMap[str])();
}
int main()
{
buildMap();
callFunc("func1");
return 0;
}
However, as I define all these things in a class, there is a compiler error occur:
#include <map>
#include <string>
#include <iostream>
using namespace std;
class theClass {
public:
typedef void (*pFunc)();
map<string, pFunc> strFuncMap;
void func1()
{
printf("this is func1!\n");
}
void buildMap()
{
strFuncMap["func1"] = &func1;// a value of type cannot be assigned to an entity of type
}
void callFunc(const std::string& str)
{
(*strFuncMap[str])();
}
};
int main()
{
theClass a;
a.buildMap();
a.callFunc("func1");
return 0;
}
I've tried to solve this problem for a couple of hours. Or is there any other way to use string to call function in a class? I will very appreciate if someone can help me. THANKS!!
Your code doesn't work because func1 is a member function and the syntax for member functions is different.
You need a map of member function pointers (offsets)
typedef void (theClass::*pFunc)();
map<string, pFunc> strFuncMap;
Then you can store the pointer with
strFuncMap["func1"] = &theClass::func1;
And you need an object to call a member function
(this->*strFuncMap[str])();
The final code:
#include <map>
#include <string>
#include <iostream>
using namespace std;
class theClass {
public:
typedef void (theClass::*pFunc)();
map<string, pFunc> strFuncMap;
void func1()
{
printf("this is func1!\n");
}
void buildMap()
{
strFuncMap["func1"] = &theClass::func1;
}
void callFunc(const std::string& str)
{
(this->*strFuncMap[str])();
}
};
int main()
{
theClass a;
a.buildMap();
a.callFunc("func1");
return 0;
}
typedef void (*pFunc)();
This declares pFunc to be the type of function pointers. That is, the type of pointers to functions which exist at the top-level. This excludes member functions, lambda functions, and functors. Consider
using pFunc = std::function<void()>
Now your type will correctly accept anything that can reasonably be interpreted as a callable object. Note that member functions still need to be wrapped in a lambda, since you're closing around this.
strFuncMap["func1"] = [this]() { this->func1(); };
I am a beginner to cpp and threads. Referred to some code snippets in stackoverflow to pass multiple arguments to a pthread function and came up with the below code. I am not sure how to access the struct members inside the function using (void*) pointer passed to it. Can anyone explain?
#include <iostream>
#include <pthread.h>
#include <vector>
using namespace std;
struct a{
vector <int> v1;
int val;
};
void* function(void *args)
{
vector <int>functionvector = (vector <int>)args->v1;
functionvector.push_back(args->val);
return NULL;
}
int main()
{
pthread_t thread;
struct a args;
pthread_create(&thread, NULL, &function, (void *)&args);
pthread_join(thread,NULL);
for(auto it : args.v1)
{
cout<<it;
}
return 0;
}
Getting the error :
error: ‘void*’ is not a pointer-to-object type
You cannot access the members of a until you have cast the void* back to an a*.
void* function(void *ptr)
{
a* args = static_cast<a*>(ptr);
args->v1.push_back(args->val);
return NULL;
}
#include <iostream>
#include <stdio.h>
#include <stdint.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
class FooBar{
public:
typedef void(FooBar::*OnDio)(void);
void OnDio0Irq( void ){
printf("dio0\n");
};
void OnDio1Irq( void ){
printf("dio1\n");
};
FooBar(){
OnDio dioArray[] = {&OnDio0Irq, &OnDio1Irq};
};
OnDio *dioArray[2];
private:
};
int main(int argc, char* argv[]){
typedef void(FooBar::*OnDio)(void);
void (FooBar::*foo)(void);
OnDio *myPtr;
FooBar *fb = new FooBar();
myPtr = *(&fb->dioArray[0]);
foo = (OnDio &)(myPtr[0]);
(foo)();//me need call fb->dioArray[0]()
(*myPtr)(); // ?
}
How can I call a function from an array?
In my code i have error:
[Error] must use '.' or '->' to call pointer-to-member function in 'foo
(...)', e.g. '(... ->* foo) (...)'
[Error] must use '.' or '->' to call pointer-to-member function in
'* myPtr (...)', e.g. '(... ->* * myPtr) (...)'
To call a pointer to member function (ptmf), you need an instance and the ptmf, together.
OnDio is already typedef'ed to be a pointer type, so you may not want OnDio pointers.
Also, you initialize a local temporary in the constructor, not the dioArray of "this" instance.
This answer is also helpful: C++: Array of member function pointers to different functions
Here is your code, corrected to call dio0 through a pointer to member function.
#include <iostream>
#include <stdio.h>
#include <stdint.h>
class FooBar {
public:
typedef void(FooBar::*OnDio)(void);
void OnDio0Irq(void) {
printf("dio0\n");
};
void OnDio1Irq(void) {
printf("dio1\n");
};
FooBar() {
// declaring a local OnDio array just masks the actual member and then it gets tossed
// need to initialize this instance, not some local temporary
dioArray[0] = &FooBar::OnDio0Irq;
dioArray[1] = &FooBar::OnDio1Irq;
};
OnDio dioArray[2];
private:
};
int main(int argc, char* argv[]) {
// need instance
FooBar fb;
// need pointer to member function
FooBar::OnDio func = fb.dioArray[0];
// call pointer to member function using instance
(fb.*func)();
}
#include <iostream>
#include <stdio.h>
#include <stdint.h>
class FooBar {
public:
typedef void(FooBar::*OnDio)(void);
OnDio dioArray[2];
void OnDio0Irq(void) {
printf("dio0\n");
};
void OnDio1Irq(void) {
printf("dio1\n");
};
FooBar() {
dioArray[0] = &FooBar::OnDio0Irq;
dioArray[1] = &FooBar::OnDio1Irq;
};
private:
};
int main(int argc, char* argv[]) {
FooBar* fb = new FooBar();
for (int i = 0; i < sizeof(fb->dioArray) / sizeof(fb->dioArray[0]); i++)
{
(fb->*fb->dioArray[i])();
}
}
I am in a code base where there are lots of function calls to functions that take a pointer as an argument. However, the function call passes a "string" object as if it's pointer. The following code is shown to give you an idea.
#include <vector>
#include <unordered_map>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
using namespace std;
void dum(char *s) {
printf("%s\n", s);
}
operator char* (string s) {
return s.c_str();
}
int main(int argc,char *argv[]) {
string st("Hello world");
dum(st);
return 0;
}
I am not allowed to change the syntax for all these functions or function calls. One possible solution I came up is to add a operator overload, but unfortunately it doesn't work, here is the error from g++ (ver 4.7.3), command line: g++ -std=c++11 te2.cc
error: ‘operator char*(std::string)’ must be a nonstatic member function
Any ideas? Thanks.
UPDATE1
#ferruccio's answer reminded me to mention that there are function calls like
dum(dum2());
where dum2() is a function is like:
string dum2() {
string s;
//.....
return s;
}
So the wrapper like the following doesn't work (), compiler gives error no matching function for call to ‘dum(std::string)’
void dum(string &s) {
dum(s.c_str());
}
operator char* (string s) {
return s.c_str();
}
This is broken (if it was allowed). When this function returns, s no longer exists. So a pointer to its contents is of no use.
You could add a simple function overload for each function that takes a char*. e.g.
void dum(const string& s) {
dum(s.c_str());
}
I have a C library function that expects a function pointer for callback, and I want to pass in a C++ member function. The C++ function modifies a member variable, so I can't use a static free function (as suggested in several similar posts). My attempt (shown below) fails with a compiler error.
This post comes closest to what I need:
Using a C++ class member function as a C callback function
How can I do this without static functions? Thanks!
test.h
#ifndef TEST_H_
#define TEST_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*handler_t)(int foo, void *bar);
void set_handler(handler_t h);
#ifdef __cplusplus
}
#endif
#endif
test.c
#include "test.h"
#include <stdlib.h>
static handler_t handler_ = NULL;
void set_handler(handler_t h) {
handler_ = h;
}
void handle_event(int foo, void *bar) {
if (handler_ != NULL) handler_(foo, bar);
}
test.cpp
#include "test.h"
#include <iostream>
using namespace std;
class Foo {
public:
Foo() : ctr_(0) {};
// handler needs to access non-static variable, so it can't be static
void handler(int foo, void *bar) { ++ctr_; }
private:
int ctr_;
};
int main(int argc, char **argv) {
// error: can't convert to "void (*)(int, void*)"
set_handler(&Foo::handler);
cout << "done" << endl;
return 0;
}
GCC barf
$ gcc test.cpp test.c
test.cpp: In function ‘int main(int, char**)’:
test.cpp:18: error: cannot convert ‘void (Foo::*)(int, void*)’ to ‘void (*)(int, void*)’ for argument ‘1’ to ‘void set_handler(void (*)(int, void*))’
It is not possible, at least with that handler_t signature.
While you can create a free function on your .cpp to wrap the member call, you need a pointer to the Foo instance:
void my_wrap(int foo, void* bar) {
Foo* some_foo_instance = ...;
some_foo_instance->handler(foo, bar);
}
int main(int argc, char **argv) {
set_handler(&my_wrap);
}
You need some void* to pass the Foo instance as a handler attribute:
// Header
typedef void (*handler_t)(int foo, void *bar, void* arg1);
void set_handler(handler_t h, void* arg1);
// Impl.
void set_handler(handler_t h, void* arg1) {
handler_ = h;
handler_arg1_ = arg1;
}
// cpp
void my_wrap(int foo, void* bar, void* arg1) {
Foo* some_foo_instance = static_cast<Foo*>(arg1);
some_foo_instance->handler(foo, bar);
}
// main
int main(int argc, char **argv) {
Foo some_concrete_instance;
set_handler(&my_wrap, static_cast<void*>(&some_concrete_instance));
}
The big question is how many times you need to call set_handler multiple times to call methods on different objects. If this answer is one, you can do something like this:
#include <boost/function.hpp>
class HandlerContext
{
static boost::function<void (int, void*)> s_func
static void forward(int foo, void* bar)
{
s_func(foo, bar);
}
public:
static void set(boost::function<int, void*> const& f)
{
s_func = f;
set_handler(&HandlerContext::forward);
}
};
If the answer is "more than once", you can have multiple forwarding functions that get their function objects out of an array. You will need to preassign slots in this case, because the function in use will indicate which callback to make.
This sentence:
I have a C library function
This means you can NOT pass it any C++ object.
If the library you are using is a C library it does not know about C++ so it can not using anything that is C++ it can only use C stuff.
You MUST make it call a free function in you code.
Now your free function can then call a method on an object (that is why C callbacks have a void* parameter (so you can pass context to the callback)).
Suppose you create a mapping function:
Foo *inst = // some instance of Foo you're keeping around...
void wrapper(int foo, void *bar){
inst->handler(foo, bar);
}
Then use wrapper as the callback. Instance semantics in a callback are kind of strange, so I'm not sure how you're going to be sure you bind to the correct instance -- if this is a singleton maybe that doesn't matter.
Here is an ugly hack I invented awhile ago to solve this problem:
#include <boost/function.hpp>
#include <boost/bind.hpp>
using ::boost::function;
using ::boost::bind;
typedef int (*callback_t)(const char *, int);
typedef function<int(const char *, int)> MyFTWFunction;
template <MyFTWFunction *callback>
class callback_binder {
public:
static int callbackThunk(const char *s, int i) {
return (*callback)(s, i);
}
};
extern void register_callback(callback_t f);
int random_func(const char *s, int i)
{
if (s && *s) {
return i;
} else {
return -1;
}
}
MyFTWFunction myfunc;
class FooClass {
public:
virtual int callme(const char *s, int x) { return 0; };
};
int main(int argc, const char *argv[])
{
FooClass foo;
myfunc = bind(&FooClass::callme, &foo, _1, _2);
register_callback(&callback_binder<&myfunc>::callbackThunk);
return 0;
}
This could probably be fixed to use stuff from TR1 and remove the dependency on Boost.
And also, of course, myfunc is a global variable. It has to be a global variable. You must have one global variable per different possible object you'd want to call back into. OTOH, you can have as many of these globals as you want.
The main issue here is that it is absolutely impossible to do what you want within the given constraints. The pointer to the object you want to call back into has to come from somewhere. In some languages (like Python for example) you can create a function on-the-fly that has it's own copy of the object pointer. This cannot be done in C++. All functions must exist completely at compile time. You cannot create new function instances at run time.
With C++0x, you can sort of create functions at runtime with lambda functions. But these functions have an unspecified type and there is absolutely no way you could ever then pass them to a C function and have it work. Lambda expressions are meant to be supplied as template parameters and it's pretty hard to use them for anything else because their address can't be taken, and even if it could you ccouldn't actually know what type the pointer is pointing to.
I highly recommend not using it. The little void * most callback interfaces allow you to specify that gets handed back to you along with the data is meant to hold an object pointer of some kind. If possible, you should be doing that instead.
If you have control over how handler is defined, I recommend using Boost function objects instead of function pointers.
If you HAVE to use function pointers, define handler_t with an extra void* whose value is passed along with the handler, watch out for the gotchas Martin York linked in a comment. Then you have something like this:
typedef void (*handler_t)(int foo, void *bar, void *data);
static handler_t handler_ = NULL;
static void* handler_data_ = NULL;
void set_handler(handler_t h, void *d = NULL) {
handler_ = h;
handler_data = d;
}
void handle_event(int foo, void *bar) {
if (handler_ != NULL) handler_(foo, bar, handler_data_);
}
void foo_handler(int foo, void *bar, void *data) {
Foo *fooObj = static_cast<Foo*>(data);
fooObj->handler(foo, bar);
}
// in main
set_handler(foo_handler, &some_foo_object);