繁体   English   中英

错误:使用复制和交换习语的交换 function 中“操作员 =”的模糊重载

[英]error: ambiguous overload for 'operator=' in swap function using the copy-and-swap idiom

在具有常量引用作为成员的 class 中使用复制和交换习语时,会发生上述错误。

示例代码:

#include <iostream>
#include <functional>

using std::reference_wrapper;

class I_hold_reference;
void swap(I_hold_reference& first, I_hold_reference& second);

class I_hold_reference{
    inline I_hold_reference(const int& number_reference) : my_reference(number_reference){}
    friend void swap(I_hold_reference& first, I_hold_reference& second);
    inline I_hold_reference& operator=(I_hold_reference other){
        swap(*this, other);
        return *this;
    }
    inline I_hold_reference& operator=(I_hold_reference&& other){
        swap(*this, other);
        return *this;
    }
private:
    reference_wrapper<const int> my_reference;
};

void swap(I_hold_reference& first, I_hold_reference& second){
    first = I_hold_reference(second.my_reference); //error: use of overloaded operator '=' is ambiguous (with operand types 'I_hold_reference' and 'I_hold_reference')
}

当 Copy 赋值运算符被更改为通过引用而不是按值获取其参数时,该错误已得到修复。

    inline I_hold_reference& operator=(I_hold_reference& other){ ... }

为什么这可以修复错误? 一种可能的含义是链接问题中引用的重要优化可能性丢失了。 参考文献是这样吗? 这种变化的其他影响是什么?

有一个依赖此运算符的代码库,不存在其他成员,只有提到的引用。 是否需要以某种方式使代码库适应这种变化,或者它是否安全?

如果您仔细按照链接的描述进行操作,您会发现您必须只有一个operator=重载,并且需要按值获取其参数。 因此,简单地删除operator=(I_hold_reference&&)重载将使您的代码可编译。

然而,这不是唯一的问题。 您的swap不会交换,而是将second个副本分配给first ,而second保持不变。

这就是你想要的:

class I_hold_reference
{
    I_hold_reference(const int& number_reference)
     : my_reference(number_reference){}

    friend void swap(I_hold_reference& first, I_hold_reference& second)
    {
        using std::swap;
        swap(first.my_reference, second.my_reference);
    }

    I_hold_reference& operator=(I_hold_reference other)
    {
        swap(*this, other);
        return *this;
    }
private:
    reference_wrapper<const int> my_reference;
};

注意:我删除了不必要的inline ,因为成员函数是隐式内联的。 我还在 class 内部声明了swap function。 您可以在共享的链接中找到对此的解释。

此外,在这个特定的示例中,首先不需要使用复制和交换习语。 std::reference_wrapper不是手动维护的资源,这意味着它内置了正确的复制和移动语义。因此,在这个特定示例中,编译器生成的复制和移动运算符将具有与此处手动创建的完全相同的行为。 所以,你应该使用那些,而不是以任何方式写你自己的。 另一方面,如果这只是一个玩具示例,并且真正的 class 中更多资源需要手动管理,那么这就是 go 的方法。

使用转发引用&&将绑定到任何右值(临时/转发引用)。 这些类别也可以作为值传递,然后是模棱两可的。 也就是说,一个临时的例子是模棱两可的,因为左值不会是(使用值重载)。

其中非常量引用永远不能绑定到临时转发引用 一个const引用虽然可以,但不是模棱两可的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM