我有一个库函数(不在我的控制之下),它对可移动和可复制类型的条形图进行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));
但我不想重复输入类型名称。
答案 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);