14

在 Google C++ Style Guide 中,有一个关于运算符重载的部分有一个奇怪的声明:

重载也有令人惊讶的后果。例如,您不能转发声明重载的类 operator&

这似乎不正确,而且我找不到任何导致 GCC 出现问题的代码。有谁知道那句话是指什么?

4

6 回答 6

20

标准的 5.3.1 有“可以获取不完整类型对象的地址,但如果该对象的完整类型是声明 operator&() 为成员函数的类类型,则行为未定义(并且没有需要诊断)。”

我也不知道这一点,但正如另一位发帖人指出的那样,很容易看出它如何导致编译器生成不正确的代码。

于 2008-10-06T23:50:13.587 回答
16

我也没有听说过,但这会给重载之前和之后相同代码的潜在混淆结果:

#include <iostream>

class Foo;

void bar (Foo& foo) {
    std::cout << &foo << std::endl;
}

class Foo {
public:
    bool operator & () { return true; }
};

void baz (Foo& foo) {
    std::cout << &foo << std::endl;
}

int main () {
    Foo foo;

    bar(foo);
    baz(foo);

    return 0;
}

输出:

0x7fff092c55df
1

尽管还有其他原因导致您无论如何都不会这样做 - 重载 address-of 不能很好地与 stl 或许多通用代码一起使用。

于 2008-10-06T23:23:12.160 回答
6

我认为这种说法并不准确。像其他答案一样,我在这里猜。首先,我假设他们指的是一元 operator& 而不是二元 operator&。那是:

int x = 5;
int* p = &x; // unary &
if (x & 1)   // binary &

您可以转发声明您想要的任何类。但是,如果类重载一元运算符&,并且您在指向这些对象之一的指针上调用一元运算符&,您可能会得到不一致的行为(有时您会简单地获取地址,有时您会调用重载方法)。这很容易变成几乎不可能调试的东西。


我很高兴 fizzer 实际上查看了标准,而不仅仅是猜测。

于 2008-10-06T23:25:49.720 回答
1

由于能够重载 operator&,boost 库提供了方便的模板 addressof()来处理查找类的真实地址。并不是我建议您重载 operator&,但如果您需要,可以提供帮助。

于 2008-10-07T13:05:08.617 回答
0

编辑以考虑评论:

这是一个猜测,但转发声明的主要原因之一是能够声明指向该类的指针。编译器必须在定义之前对类做出假设——例如,指针的大小。

是否可以通过为 T 重载 operator& 来更改 T* 的大小?(编辑:评论员——我认为不是)——但是

重载 operator& 违反了哪些假设——它如何改变类?

这是一种方法。

我可以写:

class A;

void f(A& x) {
    A* xPointer = &x;
}

如果 operator&() 被重载比没有重载,这具有新的含义,编译器可能认为它可以为它生成代码,但这是错误的。

于 2008-10-06T23:09:27.477 回答
0

措辞不清楚,您当然可以前向声明类 - 但规则显然采取了您“不应该”在类重载的位置operator&

类似的规则也出现在其他编码标准中,例如JSF(pdf)规则 159 规定operator&不应重载。

于 2008-10-07T00:19:06.120 回答