How to Invoke Pointer to Member Function When It's a Class Data Member

How to invoke pointer to member function when it's a class data member?

Like this:

(obj.*obj.pf)(0, 1);

Member access (.) has a higher precedence than a pointer to member operator so this is equivalent to:

(obj.*(obj.pf))(0, 1);

Because function call also has higher precedence than a pointer to member operator, you can't do:

obj.*obj.pf(0, 1) /* or */ obj.*(obj.pf)(0, 1)

As that would be equivalent to:

obj.*(obj.pf(0, 1)) // grammar expects obj.pf to be a callable returning a
// pointer to member

How to invoke pointer to member function from static member function?

The problem is that you need two objects inside execute - one is the instance of Executor which will supply func, and the other is an instance of (a class derived from) Sample on which func will be invoked. So you have to store the object inside Executor, not the function:

class Executor {
public:
Executor(Sample *sample)
: obj(sample)
{
}

static void *execute(void *data) {
Executor *pX = static_cast<Executor*>(data);

pX->obj->doSomething();
}

private:
Sample *obj;
};

int main() { // note that `void main()` is not legal C++
A myA;
B myB;
Executor x0(&myA);
Executor x1(&myB);

externallyInvoke(&Executor::execute, &x0);
externallyInvoke(&Executor::execute, &x1);
}

A pointer to member function (such as your original void (Sample::*func)()) identifies a function within a class, but does not store the object. You'd still need to provide one to call the function.

Use pointer to member function to determine which function to call

Syntax to call a member function via member function pointer is

(this->*memf)();

You cannot magically turn the string into a member function pointer. Sloppy speaking, names of functions do not exist at runtime. If you want such mapping you need to provide it yourself. No way around that. What you can avoid is the "forest of if-else" by using a std::unordered_map:

#include <unordered_map>
#include <string>
#include <iostream>

class Karen
{
public:
void complain(std::string level) {
static const std::unordered_map<std::string, void(Karen::*)() const> m{
{"debug",&Karen::debug},
{"info",&Karen::info},
{"warning",&Karen::warning},
{"error",&Karen::error}
};
auto it = m.find(level);
if (it == m.end()) return;
(this->*(it->second))();
}

private:
void debug(void) const { std::cout << "debug\n"; }
void info(void) const { std::cout << "info\n"; }
void warning(void) const { std::cout << "warning\n"; }
void error(void) const { std::cout << "error\n"; }
};

int main() {
Karen k;
k.complain("info");
}

Live Demo

As mentioned in comments, you could use an enum in place of the string. When possible you should use the help of the compiler, which can diagnose a typo in an enum but not in a string. Alternatively you could directly pass a member function pointer to complain. Then implementation of complain would be trivial, no branching needed. Though this would require the methods to be public and the caller would have to deal with member function pointers.


If you are not allowed to use C++11 or newer you should have a serious talk with your teacher. Soon C++20 will be the de facto standard and things have changed quite a lot. I am not fluent in C++98 anymore, so here is just a quick fix of the above to get it working somehow. You cannot use std::unordered_map but there is std::map and initialization of the map is rather cumbersome:

#include <map>
#include <string>
#include <iostream>

class Karen
{
typedef void(Karen::*memf_t)() const;
typedef std::map<std::string,void(Karen::*)() const> map_t;

public:
void complain(std::string level) {
map_t::const_iterator it = get_map().find(level);
if (it == get_map().end()) return;
(this->*(it->second))();
}

private:
const map_t& get_map(){
static const map_t m = construct_map();
return m;
}
const map_t construct_map() {
map_t m;
m["debug"] = &Karen::debug;
m["info"] = &Karen::info;
m["warning"] = &Karen::warning;
m["error"] = &Karen::error;
return m;
}
void debug(void) const { std::cout << "debug\n"; }
void info(void) const { std::cout << "info\n"; }
void warning(void) const { std::cout << "warning\n"; }
void error(void) const { std::cout << "error\n"; }
};

int main() {
Karen k;
k.complain("info");
}

Live Demo

How do I call pointer-to-member functions from another class?

You need an instance to call it:

void Game::tick(){
(this->*(button1->click))();
}

Demo

How can i call a member function pointer from another member function?

You need to specify which object to call the function on:

(this->*fnPointer)();

Call C++ member function pointer without knowing which class

It looks a lot like an XY-problem. Anyway, let's try to reply to your question as it is.

A function member is bound to the type of the class to which it belongs, unless it's a static one (the latter is treated just like a plain function pointer and you don't even have to pass a pointer to an instance to call it).

Therefore you can make callFunc a function template and let it deduce the type for you:

template<typename T>
void callFunc(void (T::*func)()){
(static_cast<T*>(obj)->*func)();
}

See it up and running on wandbox.

Note that you can incur in errors when you static_cast your obj if its original type (the one you erased to put it in a void *) isn't T.


Here is the full code you can see at the link above:

#include<iostream>

class Foo{
public:
Foo(void* object): obj(object) {}

template<typename T>
void callFunc(void (T::*func)()){
(static_cast<T*>(obj)->*func)();
}

private:
void* obj;
};

class Bar{
public:
Bar(): foo(this) {}

void callSomeFunc(){
foo.callFunc(&Bar::someFunc);
}

void someFunc(){
std::cout << "hi\n";
}

private:
Foo foo;
};

int main(){
Bar bar;
bar.callSomeFunc();
return 0;
}

C++ Call Pointer To Member Function

Pointers to non-static member functions are a unique beast with unique calling syntax.

Calling those functions require you to supply not just named parameters, but also a this pointer, so you must have the Box pointer handy that will be used as this.

(box->*h)(xPos, yPos, width, height);

Class member function pointer

If the function is not static, you cannot pass it in input to a function that accepts a non-member function pointer.

Consider that a non-static member function has an implicit pointer to ClassName as its first parameter, which points to the object on which the member function is being invoked.

struct X
{
static void foo() { } // Does not have an implicit "this" pointer argument
void bar() { } // Has an implicit "this" pointer argument
};

int main()
{
void (*f)() = &X::foo; // OK: foo is static
void (*g)() = &X::bar; // ERROR! bar is non-static
}

Here, not even std::bind() will work, because the result is not convertible to a function pointer. Lambdas are convertible to function pointers, but only if they are non-capturing (and a lambda here would need to capture the object to invoke the member function on).

Therefore, the only (ugly) workaround is to have a global adapter function which invokes the member function on an object which is available through a global pointer variable. The global pointer variable is set prior to calling the function:

struct X
{
void bar() { }
};

void function_taking_a_function_pointer(void (*f)())
{
// Do something...
f();
}

X* pX = nullptr;
void bar_adapter()
{
pX->bar();
}

int main()
{
X x; // Some object I want to invoke the member function bar() on...

pX = &x; // Set the global pointer and invoke the function...
function_taking_a_function_pointer(bar_adapter);
}

If you want, you can make this slightly more flexible by turning bar_adapter into a function template, and passing the pointer-to-member-function as a template argument:

template<typename T, void (T::*mf)()>
void adapter()
{
(pX->*mf)();
}

Here is how you would use it:

#include <iostream>

struct X
{
void foo() { std::cout << "X::foo()" << std::endl; }
void bar() { std::cout << "X::bar()" << std::endl; }
};

void function_taking_a_function_pointer(void (*f)())
{
// Do something...
f();
}

X* pX = nullptr;

template<typename T, void (T::*mf)()>
void adapter()
{
(pX->*mf)();
}

int main()
{
X x; // Some object I want to invoke the member function bar() on...

pX = &x; // Set the global pointer and invoke the function(s)...

function_taking_a_function_pointer(adapter<X, &X::foo>);
function_taking_a_function_pointer(adapter<X, &X::bar>);
}

Finally, here is a live example.

Pointer to member type incompatible with object when calling member function pointer

The left operand of .* must refer to / the left operand of ->* must point at an object of the member function's containing class. The right operand can be any expression which gives the pointer-to-member value.

The containing class of the member functions you're using is YCPU, so it's not correct to have the YCPUInstruction as a left operand. I see that your expression is within another member function of YCPU, so assuming you want to use *this as the YCPU the function is called on, you want this->*. The following expression can be an ordinary . or -> expression to just get, not call, the pointer-to-member-function value from the YCPUInstruction. Since the precedence of .* and ->* are strange, excessive parentheses are quite often necessary and always recommended.

void YCPU::run_one_instruction()
{
// ...
uint16_t word = read_mem_int16(PC, SI_CS); // 0x1-0xff
YCPUInstruction op = opcodes[word & 0xFFFF];
(this->*(op.opcode))(word);
// ...
}


Related Topics



Leave a reply



Submit