C++ Member-Function Pointer

Function pointer to member function

The syntax is wrong. A member pointer is a different type category from a ordinary pointer. The member pointer will have to be used together with an object of its class:

class A {
public:
int f();
int (A::*x)(); // <- declare by saying what class it is a pointer to
};

int A::f() {
return 1;
}

int main() {
A a;
a.x = &A::f; // use the :: syntax
printf("%d\n",(a.*(a.x))()); // use together with an object of its class
}

a.x does not yet say on what object the function is to be called on. It just says that you want to use the pointer stored in the object a. Prepending a another time as the left operand to the .* operator will tell the compiler on what object to call the function on.

Assign C++ member function to C function pointer

You simply cannot do this. Member functions have an implicit this argument that is a pointer to the object on which the function is being called. A function that does not take a B* as an argument will never manage to run on a specific B instance and a function that does not take this point as its first argument can never have the same signature as a class method. For more details on this problem and an example of a workaround read:

https://isocpp.org/wiki/faq/pointers-to-members#memfnptr-vs-fnptr

Pay attention to the note at the bottom of the answer on how static member functions can be used in such manner.

Pure C++ projects can use std::function & std::bind to achieve what you are asking about, but a C library used by a C++ project cannot work with these types.

Calling C++ member functions via a function pointer

Read this for detail :

// 1 define a function pointer and initialize to NULL

int (TMyClass::*pt2ConstMember)(float, char, char) const = NULL;

// C++

class TMyClass
{
public:
int DoIt(float a, char b, char c){ cout << "TMyClass::DoIt"<< endl; return a+b+c;};
int DoMore(float a, char b, char c) const
{ cout << "TMyClass::DoMore" << endl; return a-b+c; };

/* more of TMyClass */
};
pt2ConstMember = &TMyClass::DoIt; // note: <pt2Member> may also legally point to &DoMore

// Calling Function using Function Pointer

(*this.*pt2ConstMember)(12, 'a', 'b');

C++ Calling Member Function by Function Pointer Error

I think the syntax to invoke that member function by pointer should be e.g.

( this->*FunctionPointer )( Parameters, ReturnValue );

C++ has two operators, .* and ->*, specifically created to access class members by pointer. Here's an article on the topic. The ubiquitous * operator just doesn't work with class member pointers.

Generic member function pointer

You could create a generic templated function which accepts the signature you are interested in, pass in the instance of the object and the pointer to the member function. For example:

template<typename T>
void CallObjectMethod(int(T::*func)(int), T& obj, int val)
{
cout << (obj.*func)(val);
}

Now to call it like you mentioned in your example:

X x, x1;
CallObjectMethod(&X::echoX, x, 10);
CallObjectMethod(&X::echoX, x1, 20);

For object Y you could do something like:

Y y, y1;
CallObjectMethod(&Y::echoY, y, 10);
CallObjectMethod(&Y::echoY, y1, 20);

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

C++ Member Function Pointer Definition

Let's simplify to just considering the difference between:

template <class C, class M> void f(C (M::*member)());
template <class C, class M> void g(C (M::*member));

In f, member is a pointer to a member function of M returning taking zero arguments and returning C. If you called it with &B::func, the compiler will deduce M == B and C == void. Straightforward.

In g, member is just a pointer to a member of M of type C. But, in our case, &B::func is a function. So the impact here is just dropping the pointer. We deduce M == B again, whereas C becomes void() - now C is a function type. This is a less specialized version of f in that it allows for more kinds of members. g can match against functions that take arguments, or against pointers to members, or, relevantly, against cv-qualified member functinos.

Let's consider as an example an overloaded function and how it would get deduced differently (this was the original problem in your question, which has since been edited, but is still interesting):

struct X {
void bar() { }
void bar(int ) { }
};

When we do:

f(&X::bar);

Even though &X::bar is an overloaded name, only one actually matches C (M::*)(). The one that has M == X and C == void. There is simply no way that the overload of bar taking an int matches the template type. So this is one of the acceptable uses of passing an overloaded name. This deduces fine.

However, when we do:

g(&X::bar);

Now, there are two perfectly vaild deductions. C could be both void() and void(int). Since both are valid, the deduction is ambiguous, and you fail to compile - with an error that doesn't really make this particularly clear.


Now back to your example:

call1(&B::func2, this); // Error: no matching member function for call to 'call2'
call2(&B::func2, this); // works

The type of &B::func2 is void (B::*)() const volatile. Since call1 deduces on a member function type that takes no args and isn't cv-qualified, the type deduction simply fails. There is no C or M to get those types to match.

However, the call2 deduction is fine since it is more generic. It can match any pointer to member. We simply end up with C = void() const volatile. That's why this works.

Passing member function pointer to the c-style function

The result of std::bind is a complicated C++ object. It has to store all the bound arguments, for example. So it is most definitely not convertible to a pointer to function.

The callback specification you're dealing with apparently doesn't allow a "user data" payload, so there's nowhere to hide a pointer to a C++ object which you could use to invoke a non-static member funtion. This means you will have to call a global or static member function, or resort to a global/static member/per-thread variable to store the object pointer.

The only 100% portable way is to create a C linkage function to use as the callback. This does so, and uses a global object pointer to call your original onError():

Application *error_handling_application;

extern "C" void errorCallback(int error, const char *description)
{
error_handling_application->onError(error, description);
}

Note that quite often, you will encounter programs which use a static member function in place of my errorCallback. This works with most compilers on most platforms, but it is not guaranteed to work. The C library expects a function with C language linkage. A static member function can only have C++ language linkage. It is possible for the calling mechanism of a C function and a C++ function to differ (depends on ABI), which would result in a malformed call to the static member function passed in.

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;
}

reinterpret_cast member function pointer to void(*&)()

reinterpret_cast<T&>(x) is equivalent to *reinterpret_cast<T*>(&x).

In other words, reinterpret_cast<void(*&)()>(x) performs type punning on the pointer itself.

Accessing the result of this cast violates strict aliasing and causes undefined behavior, as usual.


I don't see any rule in the standard allowing this conversion.

Here:

[expr.reinterpret.cast]/11:

A glvalue of type T1, designating an object x, can be cast to the type “reference to T2” if an expression of type “pointer to T1” can be explicitly converted to the type “pointer to T2” using a reinterpret_­cast.
The result is that of *reinterpret_­cast<T2 *>(p) where p is a pointer to x of type “pointer to T1”. ...

Since reinterpret_cast between pointers to object types (in your case, between pointers to pointers (to [member] functions)) is always allowed, it's also allowed in your case.



Related Topics



Leave a reply



Submit