MSVC:使用内联好友运算符的union与class / struct

时间:2009-07-12 07:07:33

标签: c++ visual-c++ struct unions

这段代码在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:'
  • 将测试用例转换为struct / class 确实修复它,但这不是必需的(请不要火焰,我有理由。大多数都是C ++语言的限制)
  • 操作员方法留在全局范围(不是成员函数)

最优解决方案不会依赖于因为aestetic原因(超过24种不同的运算符和操作数组合)而在联合定义之外移动声明,但如果没有其他解决方案,则会完成。

3 个答案:

答案 0 :(得分:2)

很难说哪一个是正确的,因为标准不允许未命名的struct(尽管它们是一个共同的扩展名),因此该程序是不正确的。

编辑:这似乎是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;
}

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

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

答案 1 :(得分: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。

答案 2 :(得分: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中修复。