考虑以下自包含代码。
#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)编译得很好,没有任何错误。
您的赋值运算符按值获取参数,这需要进行复制。该副本可以(也可以不)被消除,但副本构造函数仍然需要可用和可访问,即使没有被调用。
有两个问题:
- 您的私有赋值运算符
Foo& operator=(Foo&);
采用非常量左值引用。这意味着它不能在nb = Foo<int>(10);
中被选择为重载,因为RHS是一个右值 - 这将导致您的模板分配运算符被选中。但这需要一个复制或移动复制构造函数,从而按值获取参数
如果你修复了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)
此版本被调用,但它通过值获取参数,并且必须调用复制构造函数。