76

I'm trying to do some testing with member function pointer. What is wrong with this code? The bigCat.*pcat(); statement doesn't compile.

class cat {
public:
   void walk() {
      printf("cat is walking \n");
   }
};

int main(){
   cat bigCat;
   void (cat::*pcat)();
   pcat = &cat::walk;
   bigCat.*pcat();
}
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
Nayana Adassuriya
  • 23,596
  • 30
  • 104
  • 147

2 Answers2

134

More parentheses are required:

(bigCat.*pcat)();
^            ^

The function call (()) has higher precedence than the pointer-to-member binding operator (.*). The unary operators have higher precedence than the binary operators.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • @AdrianCornish: Nope, but `pcat` does not name a member, it names the pointer-to-member declared as a local variable in `main`. – James McNellis Aug 30 '12 at 02:28
  • I guess it is a little like a virtual function call - Is there a good use case/problem this is good for - struggling to think how to use this for good code – Adrian Cornish Aug 30 '12 at 02:31
  • 1
    @AdrianCornish: I have never actually used this feature, nor have I seen it used in code written by others. Surely it has been used by someone... but the use cases are few and far between. – Ed S. Aug 30 '12 at 02:37
  • @EdS. My thoughts exactly - just because you does not mean it is a good idea ;-) never seen this in 22 years of c++ but probably a lot I have not seen too – Adrian Cornish Aug 30 '12 at 02:38
  • 1
    @AdrianCornish: It's a rarely used feature. I used it a lot in generic code, for example, I had a set of `for_each`-like algorithms that took a sequence of pointers and called a member function on each of the pointed-to objects. It saved me from having to use ugly function binder incantations. That was before lambda expressions made that a lot easier... if I were to rewrite all of that code, I'd probably use lambdas for most of the uses. – James McNellis Aug 30 '12 at 02:39
  • @JamesMcNellis Would you mind emailing me a contrived example - I think I get what you are saying but have doubts. Hopefully you can see my email from my profile. Or stick it in a pastebin – Adrian Cornish Aug 30 '12 at 02:41
  • @AdrianCornish Here's a recent (last month) use case from my experience, I set up a traits class that gives me a member function pointer to the simple primary key accessor in each ORM object for which the trait is specialized. I see member function pointers around now and again, they don't appear unusual to me (although mem_fn, bind, and friends are replacing them) – Cubbi Aug 30 '12 at 02:59
  • @AdrianCornish: I'll try to come up with one. I no longer have access to the code base in which I made extensive use of this feature, but I'm sure I can come up with something. :-) – James McNellis Aug 30 '12 at 03:00
  • @JamesMcNellis Appreciated if you could - always good to learn new techniques. – Adrian Cornish Aug 30 '12 at 03:08
  • @Adrian Cornish: I can think of one really good use case for this code. If you want to simulate something like a C# Delegate in C++, you can create a templated function object which takes a context (this pointer) and a member function that can be called later. By providing a series of templated call operators, you wrap a member function in a custom delegate for a wide variety of member function signatures. I've done this and it can be quite useful. – David Peterson Dec 29 '13 at 18:35
  • 1
    I find myself using it when refactoring and I see the same logic before and after a member-function call repeated again and again. That can get refactored into a function that takes a member function pointer to call so the before and after logic can be written only once. – Ben Dec 18 '14 at 22:28
17

Today, the canonical way is using the std::invoke function template, especially in generic code. Please note, that the member function pointer comes first:

import <functional>;

std::invoke(pcat, bigCat);

What you get: Unified calling syntax for virtually anything, that is invocable.

Overhead: none.

neonxc
  • 802
  • 9
  • 21