赋值运算符重载有类似的转换(仅在 VS 中)
Posted
技术标签:
【中文标题】赋值运算符重载有类似的转换(仅在 VS 中)【英文标题】:Assignment operator overloads have similar conversions (only in VS) 【发布时间】:2015-06-02 12:50:02 【问题描述】:我有一个包含三个类(A、B 和 C)的类层次结构。 A 和 B 是基类,使用派生类型进行参数化。 C 类派生自 A 和 B。
B 类为 A 类型的对象提供了一个赋值运算符,而 C 类通过 using super::operator=
声明继承了这个赋值运算符。
当我从 A 类型的对象定义类 B 中的构造函数时,我在 Visual Studio 2013 中得到 错误: 两个重载具有相似的转换 (C2666),但是我在 gcc (4.8.2)、clang (3.4) 和 intel icc (Studio 2015) 中没有收到任何错误或警告。 (用-Wall -pedantic
编译)
这里是简化的例子:
template <class Model> struct A ;
template <class Model> struct B
B() ; // default constructor
// copy constructor for objects of type A
template <class M>
B(A<M> const&)
// assignment operator for objects of type A
template <class M>
Model& operator=(A<M> const& rhs)
return static_cast<Model&>(*this);
;
struct C : public B<C>, public A<C>
typedef B<C> super;
// copy assignment operator
C& operator=(C const& rhs) return *this;
// adopt assignment operator for A<C> from super-class
using super::operator=;
;
int main()
C c;
A<C> a;
c = a;
如果我将模板化类 A 替换为非模板化类,它也可以在 Visual Studio 中无错误地编译 - 但这不是可以解决的方法。
我的问题是:这个结构在符合标准的意义上是格式良好的,还是错误消息正确? B 中复制构造函数的 explicit
之类的说明符是否有助于解决问题?
顺便说一句:在 Visual Studio 中,我收到 警告:指定了多个赋值运算符 (C4522),因为 C 类中的复制赋值运算符。有人可以向我解释一下,为什么这会是个问题?
【问题讨论】:
【参考方案1】:GCC 和 CLANG 正确,MSVC 错误:
预期的行为是什么:
语句c=a;
使用您在B
中定义的operator=
,因为A<C>
不一定是C
。那么让我们通过手动进行类型替换来写下B<C>
的operator=
的声明:
template <class M>
C& operator=(A<M> const& rhs)
由于a
是A<C>
,这个模板的明显隐式实例化候选将是:
C& operator=(A<C> const& rhs)
这实际上是唯一可能的实例化(您可以通过显示 typeinfo 来验证 GCC 是否使用它)。
MSVC 试图做什么?
如果您将简化类 C 更改为更简约的形式,您仍然会得到error:
struct C : public B<C> // single inheritance
using B<C>::operator=; ; // nothing else
其实问题是由构造函数B(A<M> const&)
引起的:
MSVC 错误地识别了成员函数隐式特化的第二个潜在候选者。由于此构造函数允许将 A<M>
隐式转换为 B<C>
,因此候选对象是:
C& operator=(B<C> const& rhs)
但是根据 C++ 标准,编译器根本不应该这样设想:
14.8.1/6: 将对函数参数执行隐式转换,以将其转换为相应函数的类型 参数 如果参数类型不包含模板参数 参与模板参数推导。
所以这显然是 MSVC 的一个错误。
顺便说一句:
关于多个赋值运算符的警告是just an information。显然 MS 认为这可能是导致错误的常见原因。现在到核心问题...
【讨论】:
以上是关于赋值运算符重载有类似的转换(仅在 VS 中)的主要内容,如果未能解决你的问题,请参考以下文章
重载运算与类型转换——基本概念,输入和输出运算符,算术和关系运算符,赋值运算符,下标运算符,递增和递减运算符,成员访问运算符
面向对象程序设计-C++_课时30运算符重载——基本规则_课时31运算符重载——原型_课时32运算符重载——赋值_课时33运算符重载——类型转换