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)が として許可されている場合&(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 はこの標準化前の概念を維持し、メンバーへのポインターを取得しないように括弧を使用することを明示的に述べました。

于 2011-08-21T13:43:34.430 に答える