34

I found something interesting. The error message says it all. What is the reason behind not allowing parentheses while taking the address of a non-static member function? I compiled it on gcc 4.3.4.

#include <iostream>

class myfoo{
    public:
     int foo(int number){
         return (number*10);
     }
};

int main (int argc, char * const argv[]) {

    int (myfoo::*fPtr)(int) = NULL;

    fPtr = &(myfoo::foo);  // main.cpp:14

    return 0;

}

Error: main.cpp:14: error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say '&myfoo::foo'

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Mahesh
  • 34,573
  • 20
  • 89
  • 115
  • 2
    Indeed interesting. I would normally say, that you should not at all be able to take the pointer of a non-static member of a class. Because without the this pointer, it does not make sense to take the pointer. However, why the parentheses make a difference is beyond me... – Arne Aug 20 '11 at 19:46
  • 2
    @Doug It's not quite the same question. There the issue was needing the `classname::`. Also doesn't answer what I'm most curious about, which is why (in a why was this decided on sense) are the parens disallowed? – Owen Aug 20 '11 at 19:47
  • 2
    @Doug T- I don't think this is a duplicate. The underlying cause of this problem is a weird provision of the spec preventing parenthesized names of class members from being the target of `&`, while in the question you linked the issue was that the OP was using a regular function pointer instead of a member function pointer. – templatetypedef Aug 20 '11 at 19:47
  • @templatetypedef - Thanks for giving a apt title. I need to improve my naming conventions :) – Mahesh Aug 20 '11 at 19:54
  • 2
    @Doug T: There's nothing even remotely dupe about that question. – Puppy Aug 20 '11 at 20:22
  • 1
    @Arne: It's a pointer-to-member. You bind the `this` pointer later. – Lightness Races in Orbit Aug 21 '11 at 13:45

2 Answers2

30

From the error message, it looks like you're not allowed to take the address of a parenthesized expression. It's suggesting that you rewrite

fPtr = &(myfoo::foo);  // main.cpp:14

to

fPtr = &myfoo::foo;

This is due to a portion of the spec (§5.3.1/3) that reads

A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed in parentheses [...]

(my emphasis). I'm not sure why this is a rule (and I didn't actually know this until now), but this seems to be what the compiler is complaining about.

Hope this helps!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • 2
    Interesting. When this is allowed `int a = 20; int *ptr = &(a);` , I don't understand the issue with non-static member functions. – Mahesh Aug 20 '11 at 19:47
  • 1
    @Mahesh- I have no idea! I just asked this as a question: http://stackoverflow.com/questions/7134261/strange-c-rule-for-member-function-pointers – templatetypedef Aug 20 '11 at 19:51
  • 1
    I would still really like to know that the motivation was. I suspect it might have something to do with a method name having no legit meaning until it is either (1) called or (2) referenced, and so they tried to make it as clear as possible which was happening, but I don't really know. – Owen Aug 20 '11 at 19:52
  • 4
    @templatetypedef I feel like that's this question (is how I interpreted it) – Owen Aug 20 '11 at 19:53
  • 1
    I think the question was **why** – Lightness Races in Orbit Aug 21 '11 at 13:46
  • 3
    -1: **Question:** "What is the reason behind not allowing parentheses while taking the address of a non-static member function?" **Your answer:** "it looks like you're not allowed to take the address of a parenthesized expression" **Me:** ">.<" // It's also a misleading answer because of course `int a; cout << &(a);` is perfectly valid; this applies only to pointers-to-members. – Lightness Races in Orbit Aug 21 '11 at 13:51
  • @Tomalak Geret'kal- My apologies. The question has been edited since I posted this answer, and in the original wording there was nothing to suggest that the OP wanted an explanation for why the language was designed this way. You are definitely justified in the downvote, though. – templatetypedef Aug 22 '11 at 19:29
  • The question has had no substantial revisions, and you posted your answer after the question's five-minute "revisions don't get recorded" grace period... albeit only by four seconds ;) – Lightness Races in Orbit Aug 22 '11 at 20:54
18

Imagine this code:

struct B { int data; };
struct C { int data; };

struct A : B, C {
  void f() {
    // error: converting "int B::*" to "int*" ?
    int *bData = &B::data;

    // OK: a normal pointer
    int *bData = &(B::data);
  }
};

Without the trick with the parentheses, you would not be able to take a pointer directly to B's data member (you would need base-class casts and games with this - not nice).


From the ARM:

Note that the address-of operator must be explicitly used to get a pointer to member; there is no implicit conversion ... Had there been, we would have an ambiguity in the context of a member function ... For example,

void B::f() {
    int B::* p = &B::i; // OK
    p = B::i; // error: B::i is an int
    p = &i; // error: '&i'means '&this->i' which is an 'int*'

    int *q = &i; // OK
    q = B::i; // error: 'B::i is an int
    q = &B::i; // error: '&B::i' is an 'int B::*'
}

The IS just kept this pre-Standard concept and explicitly mentioned that parentheses make it so that you don't get a pointer to member.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212