C ++,在函数中取const lvalue和rvalue引用

时间:2014-07-17 05:12:01

标签: c++ rvalue-reference lvalue

我需要一些方法让他们能够通过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行左右。显然,解决方法是像在这里一样复制它们,但它感觉不对。

如何重用复制方法的代码?

2 个答案:

答案 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将被推断为Objectstd::forward<Object&>返回Object&&。由于std::forward<Object>(o)也是右值,因此将选择移动赋值运算符。