1

这段代码在 GCC 3.x 和 4.x 上按预期编译和运行:

#include <stdio.h>

typedef union buggedUnion
{   
public:
            // 4 var init constructor
        inline buggedUnion(int _i) {
            i = _i;
        }

        friend inline const buggedUnion operator - (int A, const buggedUnion &B) {
            return buggedUnion(A - B.i);
        }

        friend inline const buggedUnion operator - (const buggedUnion &A, const buggedUnion &B) {
            return buggedUnion(A.i - B.i);
        }

        int i;

} buggedUnion;

int main()
{
    buggedUnion first(10);
    buggedUnion second(5);

    buggedUnion result = 10 - (first - second);

    printf("%d\n", result.i); // 0

    return 0;
}

但是,MSVC 不会编译该代码,并抱怨:

main.cpp(60) : error C3767: '-': candidate function(s) not accessible
        could be the friend function at 'main.cpp(41)' : '-'  [may be found via argument-dependent lookup]
        or the friend function at       'main.cpp(45)' : '-'  [may be found via argument-dependent lookup]
main.cpp(60) : error C2676: binary '-' : 'buggedUnion' does not define this operator or a conversion to a type acceptable to the predefined operator

哪个编译器是正确的?如何解决?我试图在保持可移植性、灵活性和自记录代码的同时实现干净的代码(没有外部朋友方法)。

一些注意事项:

  • 这是一个显示问题的测试用例,原始数据类型更加复杂和精心设计,尽管在 MSVC 中不起作用(主编译器是 GCC,但也需要 MSVC 兼容性)。
  • 在联合声明的开头添加 'public:' 并不能解决它。
  • 在每个运营商不解决它之前添加 'public:'
  • 将测试用例转换为结构/类确实可以解决它,但这是不希望的(请不要发火,我有理由。其中大多数是 C++ 语言的限制)
  • 运算符方法将保留在全局范围内(不是成员函数)

出于美学原因(超过 24 种不同的运算符和操作数组合),最佳解决方案不会依赖于将声明移到联合定义之外,但如果没有其他解决方案,则会这样做。

4

3 回答 3

2

很难说哪个是正确的,因为struct标准不允许未命名的 s(尽管它们是常见的扩展名),因此程序格式错误。

编辑:这似乎是 msvc 中的一个错误,因为以下完全有效的代码无法编译。

union buggedUnion
{
    friend buggedUnion operator - (int A, const buggedUnion &B) {
        return B;
    }

    friend buggedUnion operator - (const buggedUnion &A, const buggedUnion &B) {
        return A;
    }

    int i;
};


int main()
{
    buggedUnion first = { 1 };
    buggedUnion second = { 1 };
    buggedUnion result = 3 - (first - second);
}

您可以通过在类之外定义函数来解决此问题。

union buggedUnion
{
    int i;
};

buggedUnion operator - (int A, const buggedUnion &B) {
    return B;
}

buggedUnion operator - (const buggedUnion &A, const buggedUnion &B) {
    return A;
}

您甚至可以通过在类中声明函数(但仍然在外部定义它们)来保留朋友状态,但我怀疑您在联合中是否需要它。

请注意,我删除了不必要的typedefinlines。

于 2009-07-12T07:28:27.237 回答
0

您需要在封闭范围内声明这些友元函数,因为一旦在类中声明它们,它们在外部范围内就不再可见。因此,要么按照 avakar 所说的将函数体移出类,要么将它们保留在类中并添加以下行以将名称重新引入封闭范围:

extern const buggedUnion operator-(const buggedUnion& A, const buggedUnion&B);

int main()
{
    ...etc

希望这可以帮助。不确定这是否是一个错误,但在我看来(?)是正确的行为,现在已正确实施,许多编译器曾经以不同的方式解释。请参阅:http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Dialect-Options.html 中的--ffriend -injection 。

于 2009-07-12T07:59:23.540 回答
0

以下代码在 Visual C++ 2008 中正确编译:

union buggedUnion
{
    int i;

    friend buggedUnion operator - (int A, const buggedUnion &B);
    friend buggedUnion operator - (const buggedUnion &A, const buggedUnion &B);
};

buggedUnion operator - (int A, const buggedUnion &B)
{
    return B;
}

buggedUnion operator - (const buggedUnion &A, const buggedUnion &B)
{
    return A;
}

虽然 MSDN 文档指出在类中编写友元函数的定义实际上将函数置于文件范围内,但这似乎不适用于联合。由于它适用于类和结构,我怀疑这可能是一个错误。由于我上面给出的实现应该在 GCC 上工作,我认为它可以被认为是一个合适的解决方法,并且该错误可能不会在 MSVC 中修复。

于 2009-07-12T08:00:43.550 回答