调用了Copy构造函数而不是赋值运算符

Copy Constructor invoked instead of assignment operator

本文关键字:赋值运算符 构造函数 Copy 调用      更新时间:2023-10-16

考虑以下自包含代码。

#include <iostream>
template<typename Ty>
class Foo {
private:
    Ty m_data;
public:
    Foo() :m_data() {}
    Foo(Ty data) :m_data(data) {}
    template<typename U>
    Foo& operator=(Foo<U> rv)
    {
        m_data = rv.m_data;
        return *this;
    }
private:
    Foo(Foo&);
    Foo& operator=(Foo&);
};
int main()
{
    Foo<int> na(10);
    Foo<int> nb;
    nb = Foo<int>(10); // (1)
    Foo<int>(10); // (2)
}

我的理解是,陈述(1)是一项任务,而不是一个复制指令。然而,当编译(VC++和G++)时,错误消息指出,它试图匹配被声明为私有的复制构造函数。

1>Source.cpp(23): error C2248: 'Foo<int>::Foo' : cannot access private member declared in class 'Foo<int>'
1>          Source.cpp(16) : see declaration of 'Foo<int>::Foo'

我的问题是,为什么它试图搜索复制构造函数而不是赋值。

注意,我知道是赋值失败了,因为(2)编译得很好,没有任何错误。

您的赋值运算符按值获取参数,这需要进行复制。该副本可以(也可以不)被消除,但副本构造函数仍然需要可用和可访问,即使没有被调用。

有两个问题:

  1. 您的私有赋值运算符Foo& operator=(Foo&);采用非常量左值引用。这意味着它不能在nb = Foo<int>(10);中被选择为重载,因为RHS是一个右值
  2. 这将导致您的模板分配运算符被选中。但这需要一个复制或移动复制构造函数,从而按值获取参数

如果你修复了1。为了获取const参考,gcc给出以下错误:

错误:'Foo&Foo::operator=(const Foo&)[with Ty=int]'是专用

如果你修复2。使得模板赋值运算符采用const引用,代码编译无误。

您的赋值运算符按值传递参数,因此它使用复制ctor:

template<typename U>
Foo& operator=(Foo<U> rv)

通过常量引用传递的可能解决方案:

template<typename U>
Foo& operator=(const Foo<U> &rv)

专用版本

private:
    Foo(Foo&);
    Foo& operator=(Foo&);

无法调用,因为它采用了非常量左值引用,因此

Foo& operator=(Foo<U> rv)

此版本被调用,但它通过值获取参数,并且必须调用复制构造函数。