问题描述
关于std::forward的建议通常限于完全转发函数模板参数的规范用例; 一些评论员甚至说这是的 only 有效使用.但是考虑这样的代码:
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没有完美的转发?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!