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

发布于 2024-11-30 11:55:55 字数 733 浏览 4 评论 0原文

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

这个最近的问题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 [...]

有谁知道为什么规范有这个规则吗?它特定于指向成员的指针,因此我怀疑这会解决一些语法上的歧义,但老实说,我根本不知道它可能是什么。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

溺渁∝ 2024-12-07 11:55:55

这只是个人意见。
如果允许 &(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) 表示法,编译器就不需要
处理成员类型。
由于成员类型始终以指向它的指针的形式处理,
我猜标准优先考虑简化编译器的类型
系统一点。

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.

许你一世情深 2024-12-07 11:55:55

想象一下这段代码:

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; // 好的
    p = B::i; // 错误:B::i 是 int
    p = &i; // 错误:'&i' 意味着 '&this->i' 是一个 'int*'

    int *q = &i; // 好的
    q = B::i; // 错误:'B::i 是一个 int
    q = &B::i; // 错误:'&B::i' 是 'int B::*'
}

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文