C2280试图引用已删除的功能

时间:2016-02-25 18:06:29

标签: c++ visual-c++

以下代码触发此错误:

1>main.cpp(38): error C2280: 'CSet<uint32>::CSetHelper &CSet<uint32>::CSetHelper::operator =(const CSet<uint32>::CSetHelper &)': attempting to reference a deleted function
1>main.cpp(27): note: compiler has generated 'CSet<uint32>::CSetHelper::operator =' here

代码

typedef unsigned int uint32;

template<class I> class CSet
{
protected:
    uint32  u4Bits;
public:
    class CSetHelper
    {
    protected:
        uint32& ru4Var;
        uint32  u4Mask;
    public:
        CSetHelper(uint32& ru4_var, uint32 u4_mask)
            : ru4Var(ru4_var), u4Mask(u4_mask) {}
        operator uint32 () const
        {
            return ru4Var & u4Mask;
        }
        void operator =(uint32 i)
        {
            if (i)
                const_cast<uint32&>(ru4Var) |= u4Mask;
            else
                const_cast<uint32&>(ru4Var) &= ~u4Mask;
        }
    };
    CSet() : u4Bits(0) {}
    CSetHelper operator [](I i)
    {
        return CSetHelper(u4Bits, 1 << i);
    }
};

int main(int argc, char** argv)
{
    CSet<uint32> sFlags;
    sFlags[0] = sFlags[1];
    return 0;
}

这是在VS2015中,我知道他们对编译器所做的更改(detailed here)。但我不明白为什么它会触发。

理论上它应该使用正确的转换和赋值运算符,但它似乎并不是。

更新

使用Ideone.com和GCC 5.1:

prog.cpp: In member function 'CSet<unsigned int>::CSetHelper& CSet<unsigned int>::CSetHelper::operator=(const CSet<unsigned int>::CSetHelper&)':
prog.cpp:8:8: error: non-static reference member 'uint32& CSet<unsigned int>::CSetHelper::ru4Var', can't use default assignment operator
  class CSetHelper
        ^
prog.cpp: In function 'int main(int, char**)':
prog.cpp:45:12: note: synthesized method 'CSet<unsigned int>::CSetHelper& CSet<unsigned int>::CSetHelper::operator=(const CSet<unsigned int>::CSetHelper&)' first required here 
  sFlags[0] = sFlags[1];

所以似乎问题是参考成员。我可以通过将其作为指针来修复它,但我想知道它为什么不能默认复制它。

2 个答案:

答案 0 :(得分:1)

课程CSetHelper包含参考uint32& ru4Var;

编译器为这些类型创建赋值运算符和复制构造函数为已删除(= delete),因为无法重新定位引用。

答案 1 :(得分:1)

编译器是正确的。此代码格式错误。我们来看看这一行:

sFlags[0] = sFlags[1];

编译器可以采用两种方法来完成该操作:

CSetHelper& operator=(const CSetHelper&) = delete;  // (1)
void operator=(uint32 );                            // (2), via operator uint32()

虽然第二个是可能的并且可能是你想要的,但第一个是重载分辨率的更好的候选者,因为它是完全匹配而后者涉及用户定义的转换。复制赋值运算符仍处于重载范围内 - 由于具有引用成员,它只是被隐式删除。删除的函数仍然参与重载解析,如果选中,它们只会使程序格式错误。