代码之家  ›  专栏  ›  技术社区  ›  LiraNuna

msvc:union与具有内联友元运算符的类/结构

  •  0
  • LiraNuna  · 技术社区  · 15 年前

    这段代码按照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
    

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

    一些注释:

    • 这是一个 测试用例 为了说明这个问题,原始的数据类型更加复杂和精心设计,尽管它不在MSVC中工作(主编译器是gcc,但也需要与MSVC兼容)。
    • 在联合声明的开头添加“public:”不会解析它。
    • 在每个运算符未解析它之前添加“public:”
    • 将测试用例转换为结构/类 修好它,但这是不需要的(请不要火焰,我有理由。它们大多是C++语言的局限性。
    • 运算符方法将保留在 全球范围 (不是成员函数)

    最优解不会因为美学原因(超过24种不同的运算符和操作数组合)而依赖于将声明移到联合定义之外,但如果没有其他解,则会执行。

    3 回复  |  直到 12 年前
        1
  •  1
  •   avakar    15 年前

    很难说哪一个是对的,因为没有名字 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;
    }
    

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

    注意我去掉了不必要的 typedef inline S.

        2
  •  0
  •   Zooba    15 年前

    下面的代码在VisualC++ 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文档声明在类中编写friend函数的定义实际上将该函数放在了文件范围内,但这似乎对联合不起作用。因为它适用于类和结构,所以我怀疑这可能是一个bug。由于我上面给出的实现应该在gcc上工作,我认为它可以被认为是一个合适的解决方法,并且这个bug很可能不会在msvc中修复。

        3
  •  0
  •   user2189331    15 年前

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

    extern const buggedUnion operator-(const buggedUnion& A, const buggedUnion&B);
    
    int main()
    {
        ...etc
    

    希望这有帮助。不确定是否是bug,但它出现了(?)对我来说,正确的行为,现在得到了正确的实现,这是许多编译器以前用不同的方式解释的。参见:--fffriend injection in http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Dialect-Options.html .