【问题标题】:Assignment operator overloads have similar conversions (only in VS)赋值运算符重载有类似的转换(仅在 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 类中的复制赋值运算符。有人可以向我解释一下,为什么这会是个问题?

【问题讨论】:

    标签: c++ inheritance copy-constructor assignment-operator using-declaration


    【解决方案1】:

    GCC 和 CLANG 正确,MSVC 错误:

    预期的行为是什么:

    语句c=a; 使用您在B 中定义的operator=,因为A&lt;C&gt; 不一定是C。那么让我们通过手动进行类型替换来写下B&lt;C&gt;operator= 的声明:

    template <class M> 
    C& operator=(A<M> const& rhs)
    

    由于aA&lt;C&gt;,这个模板的明显隐式实例化候选将是:

     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&lt;M&gt; const&amp;)引起的:

    • 注释掉,代码就可以编译了
    • 明确说明,代码也会编译

    MSVC 错误地识别了成员函数隐式特化的第二个潜在候选者。由于此构造函数允许将 A&lt;M&gt; 隐式转换为 B&lt;C&gt;,因此候选对象是:

     C& operator=(B<C> const& rhs)
    

    但是根据 C++ 标准,编译器根本不应该这样设想:

    14.8.1/6: 将对函数参数执行隐式转换,以将其转换为相应函数的类型 参数 如果参数类型不包含模板参数 参与模板参数推导。

    所以这显然是 MSVC 的一个错误。

    顺便说一句:

    关于多个赋值运算符的警告是just an information。显然 MS 认为这可能是导致错误的常见原因。现在到核心问题...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-18
      • 1970-01-01
      • 2016-01-04
      • 2017-10-07
      • 1970-01-01
      • 2016-11-02
      相关资源
      最近更新 更多