![](/img/trans.png)
[英]Can I typically/always use std::forward instead of std::move?
[英]Do I use std::forward or std::move here?
比方说我有:
template<class T>
struct NodeBase
{
T value;
NodeBase(T &&value)
: value(value) { }
};
我继承了它:
template<class T>
struct Node : public NodeBase<T>
{
Node(T &&value)
: NodeBase( WHAT_GOES_HERE (value)) { }
};
WHAT_GOES_HERE
应该是std::move
还是std::forward<T>
? 为什么?
因为在Node<T>
的构造函数的实现中,不知道T
是普通类型(即不是引用)还是引用,
std::forward<T>(value)
适合。
只要不知道T &&
是否绑定到右值或左值, std::forward<T>(value)
就是正确的选择。 这是这种情况,因为在构造函数中我们不知道T &&
是否等同于U &&
对于某些普通类型U
,或等效于U & &&
。
在使用std::forward
或在不同时间确定的函数调用中是否推导出T
并不重要(例如在您的示例中,其中T
是在实例化Node
模板时确定的)。
std::forward<T>(value)
将以与调用者直接调用基类构造函数相同的方式调用继承的构造函数。 也就是说,当value
是左值时,它将在左value
上调用它,当value
是右值时,它将在右value
上调用它。
可能都没有。
我怀疑你应该拥有的是:
template<class T>
struct NodeBase
{
T value;
NodeBase(NodeBase &&) = default;
NodeBase(NodeBase const&) = default; // issue: this might not work with a `T&`, but we can conditionally exclude it through some more fancy footwork
NodeBase(NodeBase &) = default;
template<typename U, typename=typename std:enable_if< std::is_convertible<U&&, T>::value >::type >
NodeBase(U &&u)
: value(std::forward<U>(u)) { }
};
template<class T>
struct Node : public NodeBase<T>
{
Node( Node & ) = default;
Node( Node const& ) = default; // issue: this might not work with a `T&`, but we can conditionally exclude it through some more fancy footwork
Node( Node && ) = default;
template<typename U, typename=typename std:enable_if< std::is_convertible<U&&, NodeBase<T>>::value >::type>
Node(U && u)
: NodeBase( std::forward<U>(u) ) { }
};
除非你做的事情非常奇怪。
非常奇怪,这意味着如果你的T
是一个int
,你只想接受移动的值到你的Node
,但是如果你的T
是一个int&
,你只接受非const lvalue int
,如果T
是一个int const&
,您接受任何可转换为int
值。
这将是一组奇怪的要求放在NodeBase
的构造函数上。 我可以想到可能出现这种情况的情况,但它们并不常见。
假设你只是想让NodeBase
存储那些数据,那么在构造函数中使用T&&
是不对的 - 如果你在NodeBase
中存储一个int
,你可能愿意复制那个int
,而不是只接受移动 -来自int
。
上面的代码就是这样 - 它允许任何可以存储在NodeBase
中的NodeBase
传递到所述NodeBase
,并具有完美的转发功能。
另一方面,如果你真的想要一组奇怪的结构限制,那么这对你来说不是正确的答案。 我在构建从通用引用参数构建的template
类型时使用了它,并且我确实想要限制传入的类型以完全匹配通用引用参数,并且如果参数是rvalue引用则存储它,并以其他方式保留对它的引用。
在您的示例中没有推断出T
T
是类模板参数,而不是函数模板参数。 所以假设你不会将引用类型用作T, T&&
将是对T的rvalue引用,因此它只会绑定到类型为T的rvalues。这些移动是安全的,所以你可以使用std::move
here。
template<class T>
struct Node : public NodeBase<T>
{
Node(T &&value)
: NodeBase( std::move (value)) { }
};
int main()
{
int i = 3;
Node<int> x(42); // ok
Node<int> y(std::move(i)); // ok
Node<int> z(i); // error
}
std::forward
通常仅适用于您具有推导类型的地方,可以是左值引用或右值引用。
template<class T>
void f(T&& x)
{
... std::forward<T>(x) ...
}
因为T&&
实际上可能是左值引用或右值引用。 这只是因为在这种情况下推断出T
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.