Function pointers on a class's member function - c++

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

Related

How to handle class function pointer

I want to be able to use a member variable to hold the address a function to call
I got the error:
cannot convert 'void (TestClass::*)(bool)' to 'void (*)(bool)' in
assignment
TestClass.cpp
#include "TestClass.h"
TestClass::TestClass()
{
_myFctPtr = &setFired;
}
void TestClass::setFired(bool isFired)
{
_fired = isFired;
}
void TestClass::updateValue()
{
(_myFctPtr)(true);
}
bool TestClass::getFired()
{
return _fired;
}
TestClass.h
#pragma once
class TestClass
{
private:
bool _fired = false;
protected:
void (*_myFctPtr)(bool);
public:
TestClass();
void setFired(bool);
void updateValue();
bool getFired();
};
The error:
cannot convert 'void (TestClass::*)(bool)' to 'void (*)(bool)' in assignment
Is showing you that pointers to class member functions have a different type from regular function pointers. This is because, in addition to the regular function arguments and return type, these functions are differentiated by the object they are called on (i.e. their this), which must be provided when invoking them.
Specifically, for a pointer to a function on TestClass which accepts a bool argument as shown here, you need to to define your field as the type void (TestClass::*)(bool):
void (TestClass::*_myFctPtr)(bool);
You can call this like so, assuming you want to invoke the method on this:
((this).*(_myFctPtr))(true);
This article provides additional useful information and advice on better, cleaner ways to invoke pointers to member functions - e.g. using std::invoke for cleaner syntax than what I provided above - but this is the bare minimum to quickly solve your issue.

Calling Member Function Pointers

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.

C++ template class: No instance of constructor matches the argument list

Comment: I'm posting this question again, since some people requested me to post the full code. Here it is:
I have a function pointer typedef that looks like this:
template<typename USER_DATA>
class RowProcessor
{
typedef void (*RowFunction)(USER_DATA, std::vector<USER_DATA> &);
RowProcessor(RowFunction, int) {};
};
and then I'm using in another class UseRowProcessor:
class UseRowProcessor {
public:
void AddUserData(SomeClass, std::vector<SomeClass> &);
void LoadUserData();
};
void UseRowProcessor::AddUserData(SomeClass c, std::vector<SomeClass> &v) {
v.push_back(c);
}
void UseRowProcessor::LoadUserData() {
RowProcessor<SomeClass> myRowProcessor(AddUserData, 1); // ERROR!!
}
So the error occurs when calling RowProcessor's constructor.
The full error message says that
no insatnce of constructor "RowProcessor<USER_DATA>::RowProcessor [with USER_DATA=SomeClass]" matches the argument list
argument types are: (void (SomeClass c, std::vector<SomeClass, std::allocator<SomeClass>> &v), std::vector<SomeClass, std::allocator<SomeClass>>)
, which I have no idea what it says except for the fact that the constructor arguments do not match..
Why doesn't my AddUserFunction match the function pointer typedef??
TEST LINK<<<<<<<<
Change the function:
void AddUserData(SomeClass, std::vector<SomeClass> &);
to static void AddUserData(SomeClass, std::vector<SomeClass> &); .
As it is a class member function, the this parameter will be added after compiler, so it is not the type of the function pointer. By changing it to static, no this parameter will be added.
As Matt said you need a static function to get this working
class UseRowProcessor {
public:
static void AddUserData(SomeClass, std::vector<SomeClass> &);
void LoadUserData();
};
Here's the completely fixed sample (there were some more issues after fixing to static).
Member functions are different from ordinary functions and this carries over to their type. There is a set of work-arounds that enable you to pass member function pointers to functions that take ordinary function pointers as their parameters, but if you have control over the code you should take a different path. Instead of accepting a function pointer accept a functor.
template<typename Functor>
int f(Functor func) {
// use func like you would a function, e.g. call it with arguments func(1, 2)
}
Now you can call f with a lambda, function object, member function pointer (after you bound it to this), or function pointer.
If you want to avoid templates, accept a std::function instead, but this should only be done if you have special reasons for it.

Restricting functions that can be passed to another function in C++

I have a class containing several very similar functions and a couple other functions that take those interchangeably functions as input.
A simpler example:
class functions{
public:
int a();
int b();
int F(int (*f)() ); //f can only be a() or b()
};
Before I put them in a class, I had something like
if(f!=a || f!=b) cout<<"error";
With the class, it seems to just get more complicated, since I believe I now need to pass a class instance or something to get rid of my error: invalid use of member function
I have just started to learn about enumerated lists, and it seems like that would do the job if I was dealing with normal variables. Can I create an enum of functions?
What is the best way to restrict functions that can be passed to another function?
I'm pursuing the static cast method, but still needing help with int F( int(*f)() );
int functions::F(int (functions::*f)() )
{
if(f==functions::a)
//gives error: invalid operands of types 'int (functions::*)()'
// and 'int (int(*)()' to binary operator =='
int x=f();
//gives error: must use ‘.*’ or ‘->*’ to call pointer-to-member
//function in 'f(...)'
int y=(functions.*f)();
//gives error: expected primary-expression before ‘.*’ token
return 0;
}
It really depends on what you want to achieve:
I'd say largely that this sort of restriction is best validated by code review rather than coding...
The other solution is to not use that construct at all, and making a Fa() and Fb() function that calls the (private) a() and b() member functions.
And the remainder of the question is "how do I call a member function of a class" -the answer to which depends highly on whether Functions has member variables that are used in a() and b() or not. If there are no member functions, then declaring the a() and b() members as static will work. On the other hand, if you want to use a "member function pointer", the syntax is int (Functions::*f) and &Functions::a respectively, and the call has to be made using an instance of Functions. so if we have Functions fun, you'd do fun.*f(). Or (*this).*f(), insice F().
You may wrap the accepted function in a class:
#include <iostream>
class Functions
{
public:
int a() { return 0; }
int b() { return 1; }
};
class Accept
{
public:
typedef int (Functions::*AcceptFunction)();
int apply(Functions& object, AcceptFunction function) {
return (object.*function)();
}
};
int main()
{
Functions functions;
Accept accept;
std::cout << accept.apply(functions, &Functions::b) << std::endl;
}
(Feel free to bundle it by making Functions a nested class in Accept)

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