std :: forward没有完美的转发? [英] std::forward without perfect forwarding?
问题描述
关于std::forward
的建议通常限于完全转发函数模板参数的规范用例; 一些评论员甚至说这是
Advice on std::forward
is generally limited to the canonical use case of perfectly forwarding function template arguments; some commentators go so far as to say this is the only valid use of std::forward
. But consider code like this:
// Temporarily holds a value of type T, which may be a reference or ordinary
// copyable/movable value.
template <typename T>
class ValueHolder {
public:
ValueHolder(T value)
: value_(std::forward<T>(value)) {
}
T Release() {
T result = std::forward<T>(value_);
return result;
}
private:
~ValueHolder() {}
T value_;
};
在这种情况下,不会出现完美转发的问题:由于这是类模板而不是功能模板,因此客户端代码必须显式指定T
,并可以选择是否以及如何对其进行重新限定.同样,std::forward
的参数也不是通用引用".
In this case, the issue of perfect forwarding does not arise: since this is a class template rather than a function template, client code must explicitly specify T
, and can choose whether and how to ref-qualify it. By the same token, the argument to std::forward
is not a "universal reference".
尽管如此,std::forward
在这里似乎很合适:我们不能仅仅将其忽略掉,因为当T
是仅移动类型时,它将不起作用,并且我们不能使用std::move
因为当T
是左值引用类型时,它将不起作用.当然,我们可以对ValueHolder
进行部分专业化处理,以对引用使用直接初始化,对值使用std::move
,但是当std::forward
执行此操作时,这似乎过于复杂.这似乎与std::forward
的含义在概念上是合理的匹配:我们试图通用地转发可能或可能不是引用的内容,只是将其转发给函数的调用者,而不是转发给我们自称为功能.
Nonetheless, std::forward
appears to be a good fit here: we can't just leave it out because it wouldn't work when T
is a move-only type, and we can't use std::move
because it wouldn't work when T
is an lvalue reference type. We could, of course, partially specialize ValueHolder
to use direct initialization for references and std::move
for values, but this seems like excessive complexity when std::forward
does the job. This also seems like a reasonable conceptual match for the meaning of std::forward
: we're trying to generically forward something that might or might not be a reference, only we're forwarding it to the caller of a function, rather than to a function we call ourselves.
这是std::forward
的合理用法吗?有什么理由要避免吗?如果是这样,首选的替代方法是什么?
Is this a sound use of std::forward
? Is there any reason to avoid it? If so, what's the preferred alternative?
推荐答案
std::forward
是有条件的move
强制转换(或更严格地说是右值强制转换),仅此而已.虽然在完美的转发上下文之外使用它会造成混淆,但是如果move
上的相同条件适用,它就可以做正确的事情.
std::forward
is a conditional move
-cast (or more technically rvalue cast), nothing more, nothing less. While using it outside of a perfect forwarding context is confusing, it can do the right thing if the same condition on the move
applies.
即使在forward
上只有薄薄的包装纸,我也会尝试使用其他名称,但是我无法想到上述情况下的好包装纸.
I would be tempted to use a different name, even if only a thin wrapper on forward
, but I cannot think of a good one for the above case.
或者使条件移动更明确.即,
Alternatively make the conditional move more explicit. Ie,
template<bool do_move, typename T>
struct helper {
auto operator()(T&& t) const
-> decltype(std::move(t))
{
return (std::move(t));
}
};
template<typename T>
struct helper<false, T> {
T& operator()(T&& t) const { return t; }
};
template<bool do_move, typename T>
auto conditional_move(T&& t)
->decltype( helper<do_move,T>()(std::forward<T>(t)) )
{
return ( helper<do_move,T>()(std::forward<T>(t)) );
}
,如果bool
为false,则为noop pass-through,如果为true,则为move
.然后,您可以使等价于std::forward
的内容更加明确,而更少地依赖于用户理解C ++ 11的奥秘秘诀来理解您的代码.
that is a noop pass-through if bool
is false, and move
if true. Then you can make your equivalent-to-std::forward
more explicit and less reliant on the user understanding the arcane secrets of C++11 to understand your code.
使用:
std::unique_ptr<int> foo;
std::unique_ptr<int> bar = conditional_move<true>(foo); // compiles
std::unique_ptr<int> baz = conditional_move<false>(foo); // does not compile
另一方面,您正在做的事情需要对rvalue和lvalue语义有相当深入的了解,因此forward
可能是无害的.
On the third hand, the kind of thing you are doing above sort of requires reasonably deep understanding of rvalue and lvalue semantics, so maybe forward
is harmless.
这篇关于std :: forward没有完美的转发?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!