1

I have some confusion about how to use a pointer to a member function that is a member data itself:

struct Foo
{
    void bar(int x)
    {    
      cout << x << endl;
    }
    double getVal(double d)
    {
       return ++d;
    }

    void(Foo::*pMemFunc)(int) = &Foo::bar;// ptr to mem func
    int(Foo::*pMemI) = &Foo::val_;// ptr to mem data
    int* pI = &val_; 
    int val_ = 57;
};


int main()
{

    Foo f, *pF = new Foo{};

    double(Foo::*pMemFun)(double) = 
  &Foo::getVal;

    cout << (f.*pMemFun)(3.14) << endl;// dereferencing a pMemFun yields a the member getVal so we need an object or pointer to call it.  
    cout << (pF->*pMemFun)(2.08) << endl;// through pointer to Foo obj

    f.Foo::pMemFunc = &Foo::bar;
    // f.Foo::pMemFunc(5);// how to use this?


     cout << "\nDone!\n";
}

So pMemFunc is a pointer to a member function but the pointer itself is a member data of class Foo so how can I call the member function it points to it?

I've tried something like this:

    f.(*f.pMemFunc)(0);

But it doesn't work. What I find harder is that accessing that member must be through an object e.g f.pMemFunc or pF->pMemFunc then dereferencing it yields a member function which needs an object to call it so I try: f.(*f.pMemFunc)(10); but I get compile-time error.

Please explain how to do it. Thank you!

  • I finally somehow get it work aftet a lot of attempts: break the exppresion into to parts:

    auto ret = f.pMemFunc; // 1
    (f.*ret)(0);// 2. works fine
    

But please explain why now it works and what happens?!

Maestro
  • 2,310
  • 7
  • 19
  • The difference between your first and your second attempt is how you set your parentheses. – ypnos Mar 15 '20 at 10:22

2 Answers2

0

I suggest you use std::function to store the function pointer as a member.

For a member function, the object is the implicit first argument to the function. You may use std::bind to bind the function to the specific object (via first argument). The advantage is that you can separate binding to the object from the function call (say, in a preparation step).

From https://de.cppreference.com/w/cpp/utility/functional/bind:

// bind to a member function
Foo foo;
auto fun = std::bind(&Foo::function, &foo, _1); // _1, _2, .. are placeholders for later arguments
fun(5);

Instead of using &Foo::function directly, a function pointer or std::function can be given as first argument to bind().

ypnos
  • 45,954
  • 14
  • 88
  • 130
  • `std::bind` does not return a `std::function`. Also lambdas should be preferred. – super Mar 15 '20 at 10:49
  • I never said it returns a std::function. Please explain your preference to lambdas. – ypnos Mar 15 '20 at 10:58
  • *I suggest you use std::function to store the function pointer as a member.* quite clearly implies that there is a use of `std::function` involved here. As for lambdas, they should be preferred over using `std::bind`. Usually they can be used to achieve the same result. Here with `std::function<...> fun = [&](...){...};`. – super Mar 15 '20 at 11:02
  • Listen. I never said that std::bind returns an std::function. Your quote doesn't say it either. I asked you why lambdas ought to be preferred and you just reiterated your statement instead of giving a reason. Although I don't have a strong opinion about this, my reason to prefer std::bind() is that it makes very explicit what it does. – ypnos Mar 15 '20 at 11:08
  • I know you didn't say that. But I still find the wording in you answer potentially confusing, so I commented. You can read more about lambdas over std::bind [here](https://stackoverflow.com/questions/17363003/why-use-stdbind-over-lambdas-in-c14). – super Mar 15 '20 at 11:12
0

Finally I've managed to get it work by looking at the previous workaround, replacing ret with its corresponding sub-expression:

       auto ret = f.pMemFunc;
       (f.*ret)(0);
       (f.*f.pMemFunc)(0);// ok

But it looks ugly using f twice. Any suggestion or tips are highly appreciated.

Maestro
  • 2,310
  • 7
  • 19