C++ 错误:';的重载不明确;运算符=';在swap函数中使用复制和交换习惯用法
在具有常量引用作为成员的类中使用时, 出现上述错误 示例代码:C++ 错误:';的重载不明确;运算符=';在swap函数中使用复制和交换习惯用法,c++,copy-and-swap,pass-by-const-reference,C++,Copy And Swap,Pass By Const Reference,在具有常量引用作为成员的类中使用时, 出现上述错误 示例代码: #包括 #包括 使用std::reference_包装器; I类保持参考; 无效交换(I_持有参考&第一,I_持有参考&第二); I类保持参考{ 内联I_hold_reference(const int&number_reference):my_reference(number_reference){} 朋友无效交换(I_hold_reference&first,I_hold_reference&second); 内联I_保持\引用
#包括
#包括
使用std::reference_包装器;
I类保持参考;
无效交换(I_持有参考&第一,I_持有参考&第二);
I类保持参考{
内联I_hold_reference(const int&number_reference):my_reference(number_reference){}
朋友无效交换(I_hold_reference&first,I_hold_reference&second);
内联I_保持\引用和运算符=(I_保持\引用其他){
掉期(*本,其他);
归还*这个;
}
内联I_保持\引用和运算符=(I_保持\引用和其他){
掉期(*本,其他);
归还*这个;
}
私人:
参考包装我的参考;
};
无效交换(I_保持参考&第一,I_保持参考&第二){
first=I_hold_reference(second.my_reference);//错误:重载运算符“=”的使用不明确(操作数类型为“I_hold_reference”和“I_hold_reference”)
}
当复制赋值运算符被更改为通过引用而不是通过值获取其参数时,错误被修复
inline I_hold_引用和运算符=(I_hold_引用和其他){…}
为什么这会修复错误?
一个可能的含义是,链接问题中引用的内容丢失。对于推荐人来说这是真的吗?
这一变化的其他影响是什么
有一个依赖于此运算符的代码库,没有其他成员,只有提到的引用。是否需要以某种方式使代码库适应这种变化,或者它是安全的 如果仔细遵循链接的描述,您将看到必须只有一个重载
操作符=
,并且需要按值获取其参数。因此,只需删除操作符=(I_hold_reference&&)
重载即可使代码可编译
然而,这不是唯一的问题。您的交换
无法交换!相反,它将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;
};
I类保持参考
{
I_保持参考(常数整数和数字参考)
:my_reference(number_reference){}
朋友无效交换(I_持有参考&第一,I_持有参考&第二)
{
使用std::swap;
交换(第一个.我的参考,第二个.我的参考);
}
I_hold_reference&运算符=(I_hold_reference other)
{
掉期(*本,其他);
归还*这个;
}
私人:
参考包装我的参考;
};
注意:我删除了不必要的inline
s,因为成员函数是隐式内联的。我还声明了类中的swap
函数。您可以在共享的链接中找到对此的解释
此外,在这个特定的示例中,首先不需要使用复制和交换习惯用法
std::reference_wrapper
不是手动维护的资源,这意味着它内置了正确的复制和移动语义。因此,在这个特定的示例中,编译器生成的复制和移动操作符的行为与这里手动创建的完全相同。所以,你应该使用这些,而不是以任何方式写你自己的。另一方面,如果这只是一个玩具示例,并且实际类中有更多的资源确实需要手动管理,那么这就是方法。使用转发引用&&
将绑定到任何右值(临时/转发引用)。这些类别也可以作为值传递,然后是不明确的。也就是说,例如,临时值是不明确的,因为左值不明确(使用值重载)
其中,非常量引用永远不能绑定到临时引用或转发引用。常量引用可以,但并不含糊。您通常不(从不?)想要一个值重载和一个右值重载,因为它们在大多数情况下(总是?)都是含糊不清的。顺便说一下,这根本不是复制和交换的习惯用法。。。这里基本上是无限递归。您不能在交换中使用
operator=
中的swap
和operator=
。您希望您的交换能够实际执行交换。在您的例子中,swap的主体应该是std::swap(first.my\u reference,second.my\u reference)
。类定义中的成员函数定义是隐式内联的
。这不是一个bug,但混乱会降低可读性。交换、复制和成员类型与此无关。这与void f(int)的情况相同;无效f(int&&);int main{f(1);}
(即同样“良好”的重载)。“如果您更改为常量引用[…]”-您应该澄清这一部分。如果用常量引用重载替换by值重载,就不会有歧义,这基本上就是我们重载operator=(a const&)
和operator=(a&&)
时经常做的事情。如果用常量引用重载替换右值重载,则会有歧义,但OP提到替换by值重载,而不是右值重载。@Holt非常感谢-我想我需要阅读有关这些重载的规则。感谢您的澄清!这就解释了歧义!哦,我犯了错误,谢谢你指出这一点!在实际代码中,我使用的不是引用包装器,而是常量引用<代码>标准::交换实际上与此不兼容,但赋值在那里有效。此外,在代码中,我使用的不是int引用,而是实际的对象(带有move赋值构造函数)。您认为这些添加的代码是有效的吗?@DavidTóth引用只能初始化,以后不能重新分配。这就是为什么swap
不能使用它的原因。此外,任何赋值运算符都不能用于具有