成员函数指针的奇怪C++规则?

tem*_*def 19 c++ pointer-to-member language-lawyer

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

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

struct X {
    void foo();
};

int main() {
    void (X::* ptr)();
    ptr = &(X::foo);   // Illegal; must be &X::foo
}
Run Code Online (Sandbox Code Playgroud)

我查了一下,发现这是由于C++ ISO规范的§5.3.1/ 3所致

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

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

Ise*_*ria 27

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

struct A { int i; };

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

int main() {
  (void) typeid( A::i );
  f( &A::i );
}
Run Code Online (Sandbox Code Playgroud)

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

  • +1我认为你是对的.:-) (6认同)
  • 记住你可以在C++ 11中说`sizeof A :: i`或`sizeof(A :: i + 42)`.你可以用括号包装名称来调用一个非静态函数:`struct A {void f(){} void g(){(f)(); ``(```这里有`void()`类型. (4认同)
  • 真棒!这似乎是正确的答案.非常感谢您发布此内容! (2认同)

Joh*_*itb 5

想象一下这段代码:

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);
  }
};
Run Code Online (Sandbox Code Playgroud)

如果没有括号的技巧,您将无法直接获取 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::*'
}
Run Code Online (Sandbox Code Playgroud)

IS 只是保留了这个标准之前的概念,并明确提到括号使得您不会获得指向成员的指针。