Lar*_*Chr 9 c++ numerical operator-overloading rvalue-reference
我有下面的数字向量模板类(用于数值计算的向量).我正在努力编写D=A+B+C所有变量都是Vector对象的地方.A,B并且C不应该修改.我的想法是使用,Vector operator+(Vector&& B)以便在(希望)Vector返回Rvalue之后B+C,所有后续添加都存储在该对象中,即为所有后续添加窃取Rvalue的存储.这是为了消除新对象的创建和所需的存储.
我的问题是,我可以从调用的每个函数的输出语句中看到,Vector operator+(Vector&& B)从未调用过.我不明白为什么,因为,如果我有一个重载虚拟函数foo(Vector& B)与foo(Vector&& B)和尝试foo(A+B+C),那么第二个功能是完全相同称为我所希望的.
很抱歉这个冗长的问题,但这是我在这里的第一个问题,我想尽量保持清醒.
关于我明显做错了什么或为什么我不应该尝试这个的任何建议,将不胜感激.
template <typename T>
class Vector
{
int n;
T* v;
Vector();
~Vector();
Vector(const Vector& B);
Vector(Vector&& B);
inline Vector operator+(const Vector& B) const;
inline Vector operator+(Vector&& B) const;
};
template <typename T>
Vector<T>::Vector(const Vector<T>& B)
{
...
}
template <typename T>
Vector<T>::Vector(Vector<T>&& B)
{
...
}
template <typename T>
Vector<T> Vector<T>::operator+(const Vector<T>& B) const
{
Vector<T> C;
...
return C;
}
template <typename T>
Vector<T> Vector<T>::operator+(Vector<T>&& B) const
{
...do stuff to B
return B;
}
Run Code Online (Sandbox Code Playgroud)
在表达式中:
D=A+B+C
Run Code Online (Sandbox Code Playgroud)
A并且B是左值,所以呼叫A+B呼叫Vector::operator(const Vector&)
返回一个rvalue,让我们调用它tmp,所以下一个子表达式是tmp+C.
C也是一个左值,所以Vector::operator(const Vector&)再次调用.返回另一个右值,让我们调用它tmp2
最后一个子表达式是D=tmp2,但您的类型没有移动赋值运算符,因此使用隐式定义的复制赋值运算符.
即你永远不会operator+在右侧使用右值调用,并且唯一具有rvalue参数的表达式是你没有为rvalues定义的赋值.
定义重载的非成员运算符会更好:
Vector operator+(const Vector&, const Vector&);
Vector operator+(Vector&&, const Vector&);
Vector operator+(const Vector&, Vector&&);
Vector operator+(Vector&&, Vector&&);
Run Code Online (Sandbox Code Playgroud)
这适用于rvalues和lvalues的任意组合.(一般来说operator+,通常应该是非会员.)
编辑:下面的替代建议不起作用,在某些情况下会导致含糊不清.
另一个替代方案,如果你的编译器支持它(我认为只有clang),那就是保留你现有的Vector::operator+(Vector&&)但是用Vector::operator+(const Vector&)一个ref-qualifier来区分你的两个重载:
Vector Vector::operator+(const Vector& v) const&
{
Vector tmp(*this);
tmp += v;
return tmp;
}
Vector Vector::operator+(const Vector& v)&&
{
*this += v;
return std::move(*this);
}
Run Code Online (Sandbox Code Playgroud)
*this当它已知为rvalue时重新使用,即当加法的左侧是rvalue时它使用移动语义,与原始代码相比,原始代码只能在右侧是rvalue时使用移动语义.(注意上面的代码假设你已按照operator+=David Rodriguez的回答中的建议定义了一个成员)