2

I'm learning the concept of passing a function as a parameter.

First I've tried pass a "free function?" (function that not belong to any class or struct) to another free function using this pointer void(*Func)(int) and it worked.

Second, a free function to a function belong to a struct using the same pointer, also worked.

But when I tried to pass a function in a struct to another function in a different struct with that same pointer, it prompted error.

Here's my code:

#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <conio.h>

using namespace std;

struct A {
    void Func_A (void (*Func)(int)) {
        (*Func)(5);
    }
};

struct B {
    void Func_B (int a) {
        cout<<a;
    }
};

int main () {
    A a;
    B b;
    a.Func_A(b.Func_B);
    char key = getch();
    return 0;
}

Here the error prompt:

[Error] no matching function for call to 'A::Func_A(<unresolved overloaded function type>)'
  • 5
    member function pointers are different from free function pointers. Possible dupe: https://stackoverflow.com/questions/2402579/function-pointer-to-member-function – 463035818_is_not_an_ai Apr 16 '19 at 10:16
  • 1
    This is not mentioned in the linked duplicate. (The linked Q/A is from 2010. It's probably too old for this.) Beginning with C++11, there is [`std::function`](https://en.cppreference.com/w/cpp/utility/functional/function) available. It has the advantage that you may pass/store free function pointers as well as object/member function pointers as long as the signature matches. (Even lambdas may be bound which effectively are the former or latter.) – Scheff's Cat Apr 16 '19 at 10:46
  • The think is, I'm not using C++ 11, since ours professor want us to understand how these things work, not just using it blindly. – Thạch Hải Đăng Apr 16 '19 at 10:59
  • In this case, I can recommend my answer to [SO: What is the meaning of this star (*) symbol in C++? — Pointer to member](https://stackoverflow.com/a/50384782/7478597) where I provided (yet another) sample for member function pointers. ;-) – Scheff's Cat Apr 16 '19 at 11:03
  • I've tried to change the pointer to void (B::*Func)(int) and call it in Func_A using (this->*Func_B), but the complier prompted that it not compatible with object type A. – Thạch Hải Đăng Apr 16 '19 at 11:21

2 Answers2

1

Consider this example:

#include <iostream>
using namespace std;

struct A {
    void Func_A (void (*Func)(int)) {
        (*Func)(5);
    }
};

struct B {
  int x;
  void Func_B (int a) {
    cout << a << " " << x;
  }
};

int main () {
    A a;
    B b1;
    b1.x = 1;
    B b2;
    b2.x = 2;
    a.Func_A(b1.Func_B);
    return 0;
}

In that example, Func_B uses both the input a and the data member x, so it is clear that the result of a call to Func_B will be different depending on the object, if it is b1 or b2 that is calling it.

You might think that taking the function pointer "b1.Func_B" would clarify that you mean the function associated with the b1 object, but that does not work because the member functions do not exist separately for each instance. The function Func_B only exists once in memory, so it is not possible to have separate function pointers for "b1.Func_B" and "b2.Func_B". So, it cannot work.

The g++ 8.2.0 compiler gives the following error message for the a.Func_A(b1.Func_B); line in the code:

error: invalid use of non-static member function ‘void B::Func_B(int)’

hinting that it would be OK to do such a thing for a static member function. That makes sense, because a static member function cannot make use of the data members of any instance, so it is more like a "free function", not dependent on any instance.

Elias
  • 913
  • 6
  • 22
1

To pass a non-static member function around, the syntax is a little different. Here is your original code, reworked to show this:

#include <iostream>

struct B {
    void Func_B (int a) {
        std::cout << a;
    }
};

struct A {
    void Func_A (void (B::*Func)(int), B &b) {
        (b.*Func) (5);
    }
};

int main () {
    A a;
    B b;
    a.Func_A (&B::Func_B, b);
    return 0;
}

Note the different function signature for Func_A and the fact that you have to pass an instance of class B when you call it.

Live demo

It's a shame you can't use C++11. std::function makes this a lot simpler and more generalised.

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48