绕过自动生成的赋值运算符(VS bug?)
Posted
技术标签:
【中文标题】绕过自动生成的赋值运算符(VS bug?)【英文标题】:Getting around the auto-generated assignment operator (VS bug?) 【发布时间】:2012-06-27 06:40:01 【问题描述】:取以下代码:
class Foo
Foo const& operator =(Foo const& rhs); // disallow
;
struct Bar
public:
Foo foo;
template <class T>
T const& operator =(T const& rhs) return rhs;
;
struct Baz : public Bar
using Bar::operator =;
;
int main()
Baz b1, b2;
b1 = b2;
编译失败,因为将使用自动生成的 Bar::operator = 赋值运算符,它尝试使用私有的 Foo::operator =。还行吧。所以我在 Bar 中添加了一个额外的成员:
Bar const& operator =(Bar const& b) return Bar::operator=<Bar>(b);
现在我们遇到了不同的问题。我有两个重载,只能使用其中一个。我正在传递一个 Baz const&。我所知道的关于 C++ 的一切都表明这应该最终使用非模板版本,因为首先选择匹配的非模板。这似乎也是 gcc 正在做的事情。 Visual Studio 似乎不同意:
error C2666: 'Bar::operator =' : 2 overloads have similar conversions
could be 'const Bar &Bar::operator =(const Bar &)'
or 'const T &Bar::operator =<Baz>(const T &)'
with
[
T=Baz
]
while trying to match the argument list '(Baz, Baz)'
我很想在这里相信 gcc,这既是因为我对 C++ 的理解证实了这一点,而且因为当它与 Visual Studio 不一致时,我通常支持 gcc,但我并不像我对此那么担心:
在我的非最小示例中,老实说,我根本不需要默认生成的赋值运算符。我会对模板操作员完成这项工作感到非常满意 - 它会正确完成。但是,因为 VS 抱怨模板和自动生成的赋值运算符之间的冲突,我实际上根本无法让该模板工作。我已经尝试了以下所有方法:
-
将赋值运算符设为私有且未实现(不起作用,因为“并非所有重载都可以访问”)
创建它(导致上述错误)
忽略它(使用默认生成的赋值运算符导致上述错误)
为该类型创建模板的特化,从而与默认赋值运算符完全匹配(根据编译器明确非法)
有人对我如何解决这个问题有什么好的想法吗?不幸的是,我的 VS 版本不支持自动生成的赋值运算符的 C++0x“删除”覆盖,所以这不是一个选项,我想不出任何其他方法来解决这个错误。
【问题讨论】:
你为什么需要这个结构?如果您有理由声明一个不可分配的类,为什么要让孩子可分配 @Martin 这是一个最小的复制示例。实际用例要复杂得多,并且涉及与问题无关的模板元编程。 可能是我弄错了:返回的 const 可能是个问题。通常 operator= 返回 & 用于链接。也许 VS 在这个方向上表现出一些奇怪的行为 在Baz
中添加一个额外的operator=
是不可取的,对吧(就像您在Bar
中添加了一个operator=
)?您希望 Baz
仅与 using Bar::operator=;
一起工作吗?
我投票支持 VC 错误。应始终首先使用非模板 - 没有歧义。
【参考方案1】:
在两个版本的赋值运算符之间解析时看到的歧义是由 Baz 定义中的“使用 Bar::operator =”引起的。
无论是在 Bar 中隐式定义还是显式定义,非模板版本都采用参数“const Bar&”,该参数与“Baz”不完全匹配,这是明确解析与模板的要求。
有很多方法可以解决这个问题,但真正的解决方案将取决于真正的来源。
为了修正这个例子,我会做这些事情:
o 防止自动生成const Bar& operator =(const Bar& b)
,因为它将使用 Foo 的赋值运算符。您已经尝试添加到 Bar 的定义中的内容将起作用:
Bar const& operator =(Bar const& b)
return Bar::operator=<Bar>(b);
o using Bar::operator =
在 Baz 的定义中需要去。将其替换为包装 Bar::operator= 的函数。如:
template <class T>
const T& operator =(const T& rhs)
return Bar::operator =(rhs);
(当然,非时髦的代码总是返回 *this -- 一个 Bar&,而不是参数的类型。)
【讨论】:
我遇到了类似的问题,这个解决方案对我有用。也许它对 OP 不起作用(因为它没有被标记为正确),但值得一试。我也在 VS 上,这似乎是一个 VS 错误,是一种解决方法。以上是关于绕过自动生成的赋值运算符(VS bug?)的主要内容,如果未能解决你的问题,请参考以下文章
创建 C 子字符串:使用赋值运算符 VS strncopy 循环,哪个更好?