Calling Member Function Pointers - c++

I am having trouble calling a function pointer inside a structure. I have used this approach before outside of classes, but now that I am trying it inside a class method using function pointers to other class methods.... I am receiving a compiler error. Here is my class:
class Myclass
{
int i;
void cmd1(int)
{}
void cmd2(int)
{}
void trans()
{
const struct
{
std::string cmd;
void (Myclass::*func)(int)
}
CmdTable[] =
{
{ "command1", &Myclass::cmd1 },
{ "command2", &Myclass::cmd2 }
};
CmdTable[0].func(i);
CmdTable[1].func(i);
}
};
The lines CmdTable[0].func(i); and CmdTable[1].func(i); both provide the following
error:
Error: expression must have (pointer-to-) function type.
I realize there are probably better ways of doing this, but I'm rather curious as to why what I've written doesn't work. Any explanation would be greatly appreciated.

The pointer-to-member-function is a pure class property. You need to combine it with a class instance in order to make a meaningful function call. For example, to use the instance *this, you can use the operator ->* and say:
(this->*CmdTable[0])(i);
Or you can use operator .* on an object value:
(*this.*CmdTable[0])(i);
The latter form is always correct. For the former, note that operator->* may be overloaded and do something unrelated.

Related

Function pointers on a class's member function

void Parser::add_func_no_arg(void (Virtual_Machine::*f)(), std::string comand)
{
command_no_arg.push_back(comand);
func_no_arg.push_back(f);
}
void Parser::prepare()
{
//add_func_no_arg(Virtual_Machine::dump,"dump"); it work when i put it in static but i cant do that
add_func_no_arg(vm.clear,"clear"); // ERROR HERE the vm.clear does not fit
}
I have those two functions to try help my create a array of pointers func_no_arg;
I can't put the vm's func in static;
Why cant i have a pointer on a function when it is "trap" whit in one objet ? maybe the type is wrong, here is some .hpp :
class Parser {
public:
/***/
void prepare();
void add_func_no_arg(void (Virtual_Machine::*f)(), std::string comand);
private:
Virtual_Machine vm;
std::vector<std::string> command_no_arg;
std::vector<void (Virtual_Machine::*)()> func_no_arg;
/***/
};
class Virtual_Machine {
public:
/***/
void clear();
/***/
}
and the compiler said this :
Parser.cpp: In member function ‘void Parser::prepare()’:
Parser.cpp:65:36: error: invalid use of non-static member function ‘void Virtual_Machine::clear()’
add_func_no_arg(vm.clear,"dump");
^
In file included from ../include/Parser.hpp:13,
from Parser.cpp:8:
../include/VM.hpp:23:14: note: declared here
void clear();
The syntax for getting a pointer-to-member is &Virtual_Machine::clear (not vm.clear), and a variable f of this type can be invoked on an instance of Virtual_Machine with the .* operator (e.g. vm.*f()).
Alternatively you could write &decltype(vm)::clear, which doesn't depend on the class name.
As written by IlCapitano you have to use a specific syntax to deal with pointer-to-members. Here is an example (compiled with g++ tmp.cpp -o tmp):
#include <iostream>
#include <string>
#include <vector>
class Virtual_Machine
{
private:
std::string name;
public:
Virtual_Machine(std::string n) : name(n) {}
void clear() { std::cout << "Clear " << name << std::endl; }
};
class Parser
{
private:
Virtual_Machine vm;
std::vector<std::string> command_no_arg;
std::vector<void (Virtual_Machine::*)()> func_no_arg;
public:
Parser(std::string vm_name) : vm(vm_name) {}
void add_func_no_arg(void (Virtual_Machine::* f)(), std::string command)
{
command_no_arg.push_back(command);
func_no_arg.push_back(f);
}
void prepare()
{
add_func_no_arg(&Virtual_Machine::clear, "clear");
}
void test()
{
(vm.*(func_no_arg[0]))();
}
};
int main()
{
Parser a("vm_a"), b("vm_b");
a.prepare();
b.prepare();
a.test();
b.test();
return 0;
}
The output of the program is:
Clear vm_a
Clear vm_b
A pointer to the member function clear of an instance of class Virtual_Machine is created with &Virtual_Machine::clear. To later call this function you have to use the operators .* or ->* with an instance of the class on the left side of the operator and the pointer to the function on the right side, like (vm.*(func_no_arg[0]))(). If the function would have parameters, you would place them in the most right pair of parentheses.
As mentioned above, the proper syntax to get a pointer to a member functions is &Class::member. The general idea behind this, is that when you declare a class, every function and types in that class belongs in a namespace named after your class. Thus the syntax for getting a pointer to member function is actually equivalent to any pointer to a function inside a namespace. Do keep in mind that access specifier still apply when trying to retrieve a pointer to a function in a class.
However, there is one big difference, in that when you declare a member function, an implicit parameter is added (this in c++), which you actually noted, which is why the type is return_type (Class::*) (parameters)
There are two way to handle this matter. The first one, as noted by others here is to use the instance when you need to call the function, by using the .* or ->* syntax (the dot or arrow are there to access the instance "internals", and the star to de-reference the function pointer).
Another way of doing this (mostly if you don't care about the object, or can't access it when you call it) is to wrap your function in an std::function, by "binding" the implicit this, and any parameter you need to, using std::bind.
By using std::function and std::bind together, you would be able to use the c-style syntax you're used to.
The example section for std::function and std::bind on cppreference show how to achieve this

Unable to call member function pointer that is inside a struct

I've been racking my brain over getting the syntax right on declaring, defining and finally calling a member function pointer inside my program.
I'm writing a window manager with Xlib, and am trying to enable the user to define all key bindings in a vector of Keybinds. The Keybind struct contains more member variables, which I have left out here for the sake of brevity.
Here's what I've got so far.
Keybind, a struct containing a member variable, func, that points to a MyClass member function.
struct MyBind {
MyBind(void (MyClass::*_func)(const XKeyEvent&))
: func(_func) {}
void (MyClass::*func)(const XKeyEvent&);
}
Declaration and populating of a vector that holds user-defined Keybinds.
// in my_class.hh
std::vector<MyBind*> my_binds_;
// in my_class.cc, constructor
my_binds_.push_back(new MyBind( &MyClass::do_this ));
my_binds_.push_back(new MyBind( &MyClass::do_that ));
At this point, everything compiles and runs.
Now, when I try to delegate work by iterating over the my_binds_ vector, things go wrong. It is worth noting that I've left out error handling and other member variable accesses for clarity.
void
MyClass::handle_input(const XKeyEvent& e)
{
for (const MyBind* my_bind: my_binds_) {
(my_bind->*func)(e); // erroneous line
}
}
This should be the correct syntax, but it fails to compile, stating error: ‘func’ was not declared in this scope (g++, similar error from clang++).
This is weird to me, as replacing the erroneous line of code with auto test = keybind->func; does compile.
What am I doing wrong? Is there a better way to handle user key bind definitions? Thanks!
It would be best to use std::function and forget about raw member-function pointers altogether. They will only bring you pain :)
The problem with you code is that you only have a pointer to a method but no object. Your bind struct should also store an object pointer to call the method on:
struct MyBind {
MyBind(MyClass *obj, void (MyClass::*_func)(const XKeyEvent&))
: obj(obj), func(_func) {}
MyClass *obj;
void (MyClass::*func)(const XKeyEvent&);
void operator()(const XKeyEvent& event) const
{
(obj->*func)(event);
}
}
And then use it like this:
void
MyClass::handle_input(const XKeyEvent& e)
{
for (const MyBind* my_bind: my_binds_) {
(*my_bind)();
}
}
I've added a call operator to the bind struct for convenience. Note that the ->* operator is applied to the object the method belongs to.
This is not an answer, rather a pointer to your answer or my so-question :)
You had to use
(this->*(my_bind->func))(e);
instead of:
(my_bind->*func)(e);
I have re-created your error msg and asked a question after many different attempts.
See this( pointer to your answer ;) ): How to call pointer to member function, which has been saved in a vector of custom struct?
MyBind holds the pointer to member function of some instance of MyClass. Therefore in order to call these function pointers, you need to explicitly tell using this keyword, for which instance of MyClass you want the func to be called.

C++: Function pointer to another class function

I have 2 classes
class B {
public:
int func(int i);
};
class A {
public:
typedef int (B::*fPtr)(int);
void run();
B* mB;
};
void A::run() {
// create a pointer
fPtr p = &(B::func);
// invoke the function
mB->*p(2); <------- Compilation Error
}
What i need is to create a pointer to func() in A's run function. I get a compilation error saying that mB is not corresponding to a function with 1 argument.
please help
You need to put parentheses around the function expression:
(mB->*p)(2);
But as others have pointed out, there's almost certainly a better way to do what you're trying to do.
Instance methods on a class always have a hidden first parameter for the this pointer, thus it is incompatible with your function pointer typedef. There is no way directly to obtain a pointer to a member function. The typical workaround is to use a "thunk" where you pass a static function that accepts a generic "catch all" parameter (such as void *) which can be statically cast to a pointer of your choosing on which you can invoke the member function. Example:
class B
{
public:
static void MyThunk(void * obj)
{
static_cast<B *>(obj)->MyRealFunc();
}
void MyRealFunc()
{
// do something here
}
// . . .
};
You can get a pointer to the static function easily as it has no 'hidden this', just reference it using B::MyThunk. If your function requires additional parameters, you can use something like a functor to capture the necesssary parameters and state.
You should definitely read this C++ FAQ Lite page which tells you much more about all this: Pointers to member functions
why can you not call mB->func(2);?
If you need different functions for B perhaps look into virtual functions and class inheritance

C++ Function Callbacks: Cannot convert from a member function to a function signature

I'm using a 3rd party library that allows me to register callbacks for certain events. The register function looks something like this. It uses the Callback signature.
typedef int (*Callback)(std::string);
void registerCallback(Callback pCallback) {
//it gets registered
}
My problem is that I want to register a member function as a callback something like this
struct MyStruct {
MyStruct();
int myCallback(std::string str);
};
MyStruct::MyStruct() {
registerCallback(&MyStruct::myCallback);
}
int MyStruct::myCallback(std::string str) {
return 0;
}
Of course, the compiler complains, saying
error C2664: 'registerCallback' : cannot convert parameter 1 from 'int (__thiscall MyStruct::* )(std::string)' to 'Callback'
I've been looking at boost libraries like function and bind, but none of those seem to be able to do the trick. I've been searching all over Google for the answer, but I don't even know what to call this, so it hasn't been much help.
Thanks in advance.
You're trying to pass a member function pointer as a normal function pointer which won't work. Member functions have to have the this pointer as one of the hidden parameters, which isn't the case for normal functions, so their types are incompatible.
You can:
Change the type of your argument to accept member functions and also accept an instance to be the invoking object
Quit trying to pass a member function and pass a normal function (perhaps by making the function static)
Have a normal function that takes an instance of your class, a member function pointer, and a std::string and use something like boost's bind to bind the first two arguments
Make the callback registration function accept a functor object, or an std::function (I think that's the name)
Numerous other ways which I won't detail here, but you get the drift.
Member functions are not convertible to the normal functions for its own good reasons. If your design allows, then make MyStruct::myCallback() a static member method and the code should work fine.
struct MyStruct {
...
static int myCallback(std::string str);
^^^^^^
};
Due to the inflexible hardcoding of an actual function type for the callback you can't use any of the normal adapting or binding tricks to help you here. The third party library really wants you to pass in a non-member function and there isn't much you can do. You may want to consider why you're trying to pass it the address of a member function, and if your design or use of the library could change.
One option, if you only need to set a single callback, is to have a static or namespace private function that refers to a singleton instance pointer, and uses that to dispatch upon callback.
If you need multiple items, then possibly a template would wrap the hackiness (untested code here, just the idea).
template <int which_callback>
struct CallbackHolderHack
{
static int callback_func(std::string str) { dispatchee_->myCallback(str); }
static MyStruct* dispatchee_;
};
template <int which_callback>
MyStruct* CallbackHolderHack::dispatchee_(0);
And use it:
CallbackHolderHack<0>::dispatchee_ = new MyStruct;
registerCallback(&CallbackHolderHack<0>::callback_func);
Depends on how you are using it.... eg a Singlton would be much simplier
struct MyStruct {
static MyStruct& Create() {
static MyStruct m; return m;
}
static int StaticCallBack(std::string str) {
return Create().Callback(str)
}
private:
int CallBack(std::string str);
MyStruct();
};
Or if you want to have many of these objects you have several choices. You would need a way to route it before the callback is called.
Since you are using C++, why not make the callback a functor object? Then you can use std::mem_fun.
Edit: Seems std::mem_fun has been deprecated in the latest C++11 standard. So std::function might be a better solution if you have a new compiler.
See this SO question for hints about using it.
class ICallBackInterface
{
public:
virtual void FireCallBack( std::string& str ) = 0;
};
std::set<ICallBackInterface*> CallBackMgr;
class MyStruct : public ICallBackInterface
{
public:
MyStruct()
{
CallBackMgr.insert( this );
}
~MyStruct()
{
CallBackMgr.erase( this );
}
virtual void FireCallBack( std::string& str )
{
std::cout << "MyStruct called\n";
}
};
void FireAllCallBack(std::string& str )
{
for ( std::set<ICallBackInterface*>::iterator iter = CallBackMgr.begin();
iter != CallBackMgr.end();
++iter)
{
(*iter)->FireCallBack( str );
}
}
This is another way to use polymorphism to achieve the same effect

How to call a function using pointer-to-member-function

I have a class:
class A {
void test_func_0(int);
void run();
typedef void(A::*test_func_t)(int);
struct test_case_t{
test_func_t test_func;
} test_case[100];
};
Now I want to call test_func() inside run():
void A::run()
{
test_case[0].test_func = &test_func_0;
test_case[0].*(test_func)(1);
}
The last line of my code, doesn't work(compile error), no matter what combination I try.
Use this:
void A::run()
{
test_case[0].test_func = &A::test_func_0;
(this->*(test_case[0].test_func))(1);
}
Notice that you had 2 errors. The first one was how you formed the member-function-pointer. Note that the only way to do it is to use &ClassName::FuncName regardless of whether you're at class scope or not. & is mandatory too.
The second is that when you call a member via a member function pointer, you must explicitly specif y the object (of type A in your case) on which to call the member function. In this case you must specify this (and since this is a pointer we use ->* rather than .*)
HTH
Use:
(this->*test_case[0].test_func)(1);
Member function call using pointer-to-member-function:
test_case[0].test_func = &A::test_func_0; //note this also!
(this->*test_case[0].test_func)(1);
Demo : http://www.ideone.com/9o8C4