数值向量运算符重载 + 右值引用参数
Numeric vector operator overload+ rvalue reference parameter
我在下面有数字向量模板类(用于数值计算的向量(。我正在尝试编写所有变量都Vector
对象的D=A+B+C
。 A
、B
和C
不应修改。我的想法是使用Vector operator+(Vector&& B)
,以便在(希望(从B+C
返回 Rvalue Vector
后,所有后续添加都存储在该对象中,即窃取 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;
}
在表达式中:
D=A+B+C
A
和 B
是左值,因此调用A+B
调用Vector::operator(const Vector&)
这返回一个右值,我们称之为 tmp
,所以下一个子表达式是 tmp+C
。
C
也是一个左值,所以它再次调用Vector::operator(const Vector&)
。这返回另一个 rvalue,我们称之为 tmp2
最后一个子表达式是 D=tmp2
,但您的类型没有移动赋值运算符,因此使用隐式定义的复制赋值运算符。
也就是说,您永远不会在右侧使用右值调用operator+
,并且唯一具有右值参数的表达式是您尚未为右值定义的赋值。
最好定义重载的非成员运算符:
Vector operator+(const Vector&, const Vector&);
Vector operator+(Vector&&, const Vector&);
Vector operator+(const Vector&, Vector&&);
Vector operator+(Vector&&, Vector&&);
这将适用于右值和左值的任意组合。(一般来说,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);
}
当已知它是右值时,这会重用*this
,即当添加的左侧是右值时,它使用移动语义,而原始代码只能在右侧是右值时使用移动语义。 (注意:上面的代码假设你已经按照David Rodriguez的回答中的建议定义了成员operator+=
(
我建议您提供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
,编译器将为第一次调用operator+
创建一个a
的副本,就地修改它(lhs += rhs
(,然后将其移动到返回值中。然后它会将该返回值(除非它省略移动(移动到第二个operator+
的参数中,在那里它将再次就地修改,然后移动到返回值。
总的来说,将创建一个新对象,保存a+b+c
的结果,提供等效的语义:
Vector<T> tmp = a;
tmp += b;
tmp += c;
但是有了更好、更紧凑的语法a + b + c
.
请注意,这不会优雅地处理a + (b+c)
,并且会创建两个对象,如果要支持它,则需要生成多个重载。
- 将const引用参数初始化为默认参数会导致悬空引用吗
- 具有常量引用参数的函数模板专用化
- C++:常量引用参数
- 字符串引用参数的效率C++
- 通过非常量引用参数修改常量引用参数
- 如何将指针变量作为引用参数传递?
- C++初始化 std::function 时如何将占位符绑定到引用/引用参数?
- 移动类的成员作为常量引用参数传递
- C++带有适用于左值和右值的引用参数的函数
- constexpr 函数的常量引用参数:gcc/msvc vs clang/icc
- 如何使用类型特征将函数的通用引用参数限制为 r 值引用?
- 委托构造函数和引用参数
- 对 const 引用参数使用默认值会导致崩溃
- 为什么我们不允许将纯引用参数传递给 std::thread,但允许传递原始指针?
- 为什么我需要将默认引用参数定义为 const 以便为其分配一个左值?
- 将非左值作为常量引用参数传递.临时是在本地作用域还是在调用方作用域中创建的?
- 如何强制函数仅接受左值引用参数
- 模板引用参数推断失败C++
- 非类型引用参数可以在运行时修改,这是否意味着模板可以在运行时实例化?
- 将unique_ptr作为引用参数或常量传递unique_ptr引用