Possible Duplicate:
Error with address of parenthesized member function
In this recent question the OP ran into a strange provision of the C++ language that makes it illegal to take the address of a member function if that member function name is parenthesized. For example, this code is illegal:
struct X {
void foo();
};
int main() {
void (X::* ptr)();
ptr = &(X::foo); // Illegal; must be &X::foo
}
I looked this up and found that it's due to §5.3.1/3 of the C++ ISO spec, which reads
A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed in parentheses [...]
Does anyone have any idea why the spec has this rule? It's specific to pointers-to-member, so I would suspect that there is some grammatical ambiguity that this resolves, but I honestly haven't the faintest idea what it might be.
This is just a personal opinion.
If &(qualified-id)
is allowed as &(unary-expression)
,
qualified-id has to be an expression, and an expression is expected to have a type
(even if it is incomplete).
However, C++ didn't have a type which denotes a member, had only
a pointer to member.
For example, the following code cannot be compiled.
struct A { int i; };
template< class T > void f( T* );
int main() {
(void) typeid( A::i );
f( &A::i );
}
In order to make &(qualified-id)
be valid, the compiler has to hold
a member type internally.
However, if we abandon &(qualified-id)
notation, the compiler doesn't need
to handle member type.
As member type was always handled in the form of a pointer to it,
I guess the standard gave priority to simplify the compiler's type
system a little.
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.