我需要一些方法让他们能够通过const lvalue(它将被复制的位置)和rvalue reference(用于速度)获取变量
struct Object {
...
Object(Object&& o) { ... }
Object(const Object& o) { ... }
...
};
...
struct SomeClass {
...
Object arr[7];
void copy(int pos,const Object& o) { arr[pos] = o; }
void copy(int pos,Object&& o) { arr[pos] = o; }
...
};
因此,SomeClass中的两个复制方法完全是IDENTICAL。唯一的区别是,一个Object作为const传递,将被复制,而另一个Object传递给快速复制作为右值参考。
这两种方法的代码完全是IDENTICAL。
现在,在上面的例子中并不是那么悲惨,但是,我的方法有点大,9-15行左右。显然,解决方法是像在这里一样复制它们,但它感觉不对。
如何重用复制方法的代码?
答案 0 :(得分:3)
首先,在两种情况下都要进行复制分配:
void copy(int pos,const Object& o) { arr[pos] = o; }
void copy(int pos,Object&& o) { arr[pos] = o; }
如果有名字,那就是左值。在第二个函数中,o
有一个名称,所以它是一个左值(尽管是一个右值引用)。你想要arr[pos] = std::move(o);
。
避免必须两次写copy
的常用方法是按值o
移动并从中移出:
void copy(int pos, Object o) { arr[pos] = std::move(o); }
如果传递左值,则 o
将被复制构建,然后移动分配到arr[pos]
。如果传递右值,o
将被移动构造,然后进一步移动 - 分配到数组中。因此,您仍然可以避免rvalue案例中的副本,但您在两种情况下都需要支付额外费用。如果动作像它们应该的那样便宜,那么额外的开销并不多。
但是,请注意,这不适用于不支持移动语义的旧类型。在这种情况下,此函数将复制您传递的内容,然后从中复制 - 分配,而引用的两个重载只执行一个副本。
答案 1 :(得分:2)
通用引用和std::forward
允许您实现完美转发。这是修改后的copy
:
template <typename T>
void copy(int pos, T&& o) {arr[pos] = std::forward<T>(o);}
如果您担心其他类型可能会隐式转换为Object
,您还可以在static_assert
的正文中添加copy
。如果您将l值Object
传递给copy
,则T
将被推断为Object&
。 std::forward<Object&>
返回引用。因此,将选择复制分配重载。如果您将r值Object
传递给copy
,则T
将被推断为Object
。 std::forward<Object&>
返回Object&&
。由于std::forward<Object>(o)
也是右值,因此将选择移动赋值运算符。