21

可能重复:
带括号的成员函数的地址错误

最近的这个问题中,OP 遇到了 C++ 语言的一个奇怪规定,如果该成员函数名称带有括号,则获取成员函数的地址是非法的。例如,此代码是非法的:

struct X {
    void foo();
};

int main() {
    void (X::* ptr)();
    ptr = &(X::foo);   // Illegal; must be &X::foo
}

我查了一下,发现这是由于 C++ ISO 规范的 §5.3.1/3 造成的,它的内容如下

仅当使用显式 & 并且其操作数是未包含在括号中的限定 ID 时,才会形成指向成员的指针 [...]

有谁知道为什么规范有这个规则?它特定于指向成员的指针,所以我怀疑这解决了一些语法歧义,但老实说,我一点也不知道它可能是什么。

4

2 回答 2

27

这只是个人意见。如果&(qualified-id)允许 as &(unary-expression),qualified-id 必须是一个表达式,并且一个表达式应该有一个类型(即使它不完整)。但是,C++ 没有表示成员的类型,只有一个指向成员的指针。例如,以下代码无法编译。

struct A { int i; };

template< class T > void f( T* );

int main() {
  (void) typeid( A::i );
  f( &A::i );
}

为了使其&(qualified-id)有效,编译器必须在内部保存一个成员类型。但是,如果我们放弃&(qualified-id)符号,编译器就不需要处理成员类型。由于成员类型总是以指针的形式处理,我猜标准优先考虑简化编译器的类型系统。

于 2011-08-20T22:06:46.340 回答
3

想象一下这段代码:

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);
  }
};

如果没有括号的技巧,您将无法直接将指针指向 B 的数据成员(您将需要基类强制转换和带有this- 不好的游戏)。


来自 ARM:

请注意,必须显式使用地址运算符来获取指向成员的指针;没有隐式转换......如果有,我们将在成员函数的上下文中产生歧义......例如,

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::*'
}

IS 只是保留了这个 pre-Standard 概念,并明确提到括号使它不会得到指向成员的指针。

于 2011-08-21T13:43:34.430 回答