数字向量运算符过载+右值引用参数 [英] Numeric vector operator overload+ rvalue reference parameter

查看:288
本文介绍了数字向量运算符过载+右值引用参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有下面的数字向量模板类(数值计算的向量)。我试着让写入 D = A + B + C ,其中所有变量都是 Vector 对象。 A B C 不应修改。我的想法是使用 Vector operator +(Vector& B),以便在(希望)之后Rvalue Vector B + C 返回,所有后续添加都存储在该对象中,即,为所有后续添加窃取Rvalue的存储。这是为了消除创建新对象和所需的存储。



我的问题是,我可以从每个函数的输出语句调用向量运算符+(向量&& B)从未被调用。我不明白为什么如果我有一个重载的虚函数 foo(Vector& B) foo(Vector& B)并尝试 foo(A + B + C),那么第二个函数的调用与我希望的完全一样。



对于长时间问题,很抱歉,这是我的第一个问题,我想尽量做到尽可能清楚。



对我的建议显然做错了,或为什么我不应该尝试这个,将不胜感激。

 模板< typename T& 
class Vector
{
int n;
T * v;
Vector();
〜Vector();
Vector(const Vector& B);
矢量(矢量& 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& T>
Vector< T> :: Vector(Vector< T>& B)
{
...
}

template<类型名T>
矢量< T> Vector< T> :: operator +(const Vector< T>& B)const
{
Vector& C;
...
return C;
}

template< typename T>
矢量< T> Vector< T> :: operator +(Vector< T>& B)const
{
... do stuff to B
return B;
}


解决方案

p>

  D = A + B + C 

$ b b

A B 都是左值,因此调用 A + B 调用 Vector :: operator(const Vector&)



rvalue,让我们称它为 tmp ,因此下一个子表达式是 tmp + C



C 也是一个左值,所以它调用 Vector :: operator(const Vector&)。返回另一个右值,让它调用 tmp2



最后的子表达式是 D = tmp2 ,但您的类型没有移动赋值运算符,因此使用隐式定义的复制赋值运算符。



即你永远不会调用右$ rvalue的运算符+ ,唯一有一个右值参数的表达式是一个你没有为右值定义的赋值。 / p>

最好定义重载的非成员运算符:

 向量运算符+(const Vector& const Vector&); 
向量运算符+(向量&&&常量向量&);
矢量运算符+(const Vector& amp;&& amp;);
向量运算符+(向量&&&&&&&

这将适用于右值和左值的任何组合。 (运算符+ 通常应该是非成员。)



编辑:



另一个替代方法,如果你的编译器支持它(我认为只有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);
}

这会重用 * this 当它被认为是一个右值,即它使用移动语义,当左侧的加法是一个右值,与你的原始代码,只能使用移动语义当右侧是右值时。 (上面的代码假设你已经定义了一个成员 operator + = ,如David Rodriguez的回答中所建议的)


I have the numeric vector template class below (vector for numerical calculations). I am trying make it possible to write D=A+B+C where all variables are Vector objects. A, B and C should not be modified. My idea is to use Vector operator+(Vector&& B) so that after (hopefully) an Rvalue Vector has been returned from B+C, all subsequent additions are stored in that object i.e. steal the storage of the Rvalue for all subsequent additions. This is in order to eliminate creation of new objects and required storage.

My problem is that I can see from output statements from each function called that Vector operator+(Vector&& B) is never called. I cannot understand why since if I have an overloaded dummy function foo(Vector& B) and foo(Vector&& B) and try foo(A+B+C), then the second function is called exactly as I hoped.

Sorry for the long winded question but this is my first question here and I want to try to be as clear as possible.

Any suggestions as to what I am obviously doing wrong or why I should not be trying this, would be appreciated.

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;
}

解决方案

In the expression:

D=A+B+C

A and B are lvalues, so the call A+B calls Vector::operator(const Vector&)

That returns an rvalue, let's call it tmp, so the next sub-expression is tmp+C.

C is also an lvalue, so it calls Vector::operator(const Vector&) again. That returns another rvalue, lets call it tmp2

The final sub-expression is D=tmp2, but your type doesn't have a move-assignment operator, so the implicitly-defined copy-assignment operator is used.

i.e. you never invoke operator+ with an rvalue on the right-hand side, and the only expression which does have an rvalue argument is an assignment which you haven't defined for rvalues.

It would be better to define overloaded non-member operators:

Vector operator+(const Vector&, const Vector&);
Vector operator+(Vector&&, const Vector&);
Vector operator+(const Vector&, Vector&&);
Vector operator+(Vector&&, Vector&&);

This will work for any combination of rvalues and lvalues. (In general operator+ should usually be a non-member anyway.)

Edit: the alternative suggestion below doesn't work, it results in ambiguities in some cases.

Another alternative, if your compiler supports it (I think only clang does,) would be to keep your existing Vector::operator+(Vector&&) but replace your Vector::operator+(const Vector&) with two overloads distinguished by a 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);
}

This reuses *this when it's known to be an rvalue, i.e. it uses move semantics when the left-hand side of the addition is an rvalue, compared to your original code which can only use move semantics when the right-hand side is an rvalue. (N.B. the code above assumes you've defined a member operator+= as suggested in David Rodriguez's answer)

这篇关于数字向量运算符过载+右值引用参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆