产生副本作为输入rvalue引用的函数

时间:2017-02-20 16:13:14

标签: c++ c++14 rvalue-reference

我有一个库函数(不在我的控制之下),它对可移动和可复制类型的条形图进行r值引用:

void foo(Bar&& b);

在我自己的代码中,我有时需要给它一个现有值的副本,例如

const auto b = getBar();
foo(mk_copy(b));
b.baz();

这就是我想到的,

template<typename T> auto mk_copy(T val){return val;}

有没有标准的方法来做到这一点,或者更常见的模式?甚至可能

template<typename T> auto mk_copy(T&& val){return std::forward<T>(val);}

或者,正如pscill指出只是再次写出该类的名称,

foo(Bar(b));

但我不想重复输入类型名称。

3 个答案:

答案 0 :(得分:1)

没有标准机制,但如果你想要一个,你的例子就不是很好。第一次mk_copy次复制T两次(或复制和移动)。第二个似乎非常混乱,它正在尝试做什么。

显而易见的方法就是像往常一样采用const T&

template<typename T> T mk_copy(const T &val){return val;}

答案 1 :(得分:1)

对于内置类型,前缀+扮演“制作副本”的角色:

void foo( char&& ) {}
void bar( double*&& ) {}

auto main() -> int
{
    char x{};
    foo( +x );

    double* p{};
    bar( +p );
}

但是,如果您将前缀+应用于其他类型,那么代码的读者可能会感到困惑,并且通用前缀operator+模板可能最终与某些类的自己的前缀冲突operator+

所以,我建议对制造商使用现在明显的命名约定,即make前缀。

然后它看起来像这样:

template< class Type >
auto make_copy( Type const& o ) -> Type { return o; }

您提出的第一个解决方案,

template<typename T> auto mk_copy(T val){return val;}

可能会将值复制两次:首先复制到by-value参数,然后复制到函数结果。

对于诸如标准库容器之类的可移动类型,这不是问题,因为返回类型复制将减少为移动。但是对于较大的不可移动类型来说,这可能是一个问题,就像传统代码中可能出现的那样。

第二个提议的解决方案,

template<typename T> auto mk_copy(T&& val){return std::forward<T>(val);}

通过转发引用(a.k.a.通用引用)获取参数,然后从重新创建参数类型中推导出返回类型。返回类型将始终是非引用,因为这是普通auto推导的,因此这在技术上是正确的。但它不必要地复杂化。

答案 2 :(得分:1)

我认为您最好定义mk_copy方法,或者再添加一个声明:

auto b_copy = b;
foo(std::move(b_copy));

这些对读者来说更清楚。

为了证明这些可能性,您可以使用decltype来获取类型:

foo(std::decay_t<decltype(b)>{b});

或者你可以用lambdas获得相同的效果:

foo([&]{return b;}());

或元组:

foo(std::get<0>(std::make_tuple(b)));

或成对:

foo(std::make_pair(b, 0).first);