Error with address of parenthesized member function
Asked Answered
L

2

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'

Leaves answered 20/8, 2011 at 19:39 Comment(6)
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...Fluxion
@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?Hatfield
@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.Livorno
@Livorno - Thanks for giving a apt title. I need to improve my naming conventions :)Leaves
@Doug T: There's nothing even remotely dupe about that question.Rhythmandblues
@Arne: It's a pointer-to-member. You bind the this pointer later.Lentha
L
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!

Livorno answered 20/8, 2011 at 19:44 Comment(8)
Interesting. When this is allowed int a = 20; int *ptr = &(a); , I don't understand the issue with non-static member functions.Leaves
@Mahesh- I have no idea! I just asked this as a question: #7134761Livorno
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.Hatfield
@Livorno I feel like that's this question (is how I interpreted it)Hatfield
I think the question was whyLentha
-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.Lentha
@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.Livorno
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 ;)Lentha
B
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.

Bostick answered 21/8, 2011 at 13:42 Comment(2)
Seems like a funny way [for the committee] to resolve the ambiguity.Lentha
@Tomalak it seems only natural to me.Bostick

© 2022 - 2024 — McMap. All rights reserved.