簡體   English   中英

數值向量運算符重載+右值參考參數

[英]Numeric vector operator overload+ rvalue reference parameter

我有下面的數字向量模板類(用於數值計算的向量)。 我正在嘗試寫D=A+B+C ,其中所有變量都是Vector對象。 不應修改ABC 我的想法是使用Vector operator+(Vector&& B)以便在(有希望)從B+C返回Rvalue Vector之后,所有后續添加都存儲在該對象中,即竊取所有后續添加的R值的存儲。 這是為了消除新對象的創建和所需的存儲。

我的問題是我可以從每個函數的輸出語句中看到,從不調用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;
}

在表達式中:

D=A+B+C

AB是左值,因此調用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&&);

這適用於rvalues和lvalues的任意組合。 (一般來說, operator+通常應該是非會員。)

編輯:下面的替代建議不起作用,在某些情況下會導致含糊不清。

另一個替代方案,如果你的編譯器支持它(我認為只有clang),那就是保留你現有的Vector::operator+(Vector&&)但用一個ref-qualifier區分的兩個重載替換你的Vector::operator+(const Vector&)

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

當它已知為rvalue時,它重用*this ,即當加法的左側是rvalue時,它使用移動語義,與原始代碼相比,當右側是右值時,它只能使用移動語義。 (注意上面的代碼假設你已經定義了一個成員operator+=正如David Rodriguez的回答中所建議的那樣)

我建議您提供operator+=作為成員方法,然后從自由函數operator+重用它定義為:

template <typename T>
Vector<T> operator+( Vector<T> lhs,              // by value
                     Vector<T> const & rhs ) {
    lhs += rhs;
    return lhs;
}

給出的呼叫a + b + c ,其中的基團(a+b) + c ,編譯器將創建的副本a用於在第一次調用operator+ ,修改到位( lhs += rhs ),然后將其移動到返回的值。 然后,它會移動一個返回值(除非它elides移動)到第二的說法operator+ ,在那里將到位再次被修改,然后移動到返回值。

總的來說,將創建一個新對象,保持a+b+c的結果,提供相當於以下內容的語義:

Vector<T> tmp = a;
tmp += b;
tmp += c;

但是使用更好,更緊湊的語法a + b + c


請注意,這不會優雅地處理a + (b+c) ,並且會創建兩個對象,如果要支持它,則需要產生多個重載。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM