![](/img/trans.png)
[英]C++ is it possible to overload the unary minus operator of an rvalue reference?
[英]Numeric vector operator overload+ rvalue reference parameter
我有下面的數字向量模板類(用於數值計算的向量)。 我正在嘗試寫D=A+B+C
,其中所有變量都是Vector
對象。 不應修改A
, B
和C
我的想法是使用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
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&&);
這適用於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.