C++ 0x显示了一个使用示例std::forward
:
template<class T>
void foo(T&& arg)
{
bar(std::forward<T>(arg));
}
Run Code Online (Sandbox Code Playgroud)
什么时候使用它std::forward
总是有利的?
另外,它需要&&
在参数声明中使用,它在所有情况下都有效吗?如果函数在其中声明,我认为你必须将临时函数传递给函数&&
,那么可以使用任何参数调用foo吗?
最后,如果我有一个函数调用,如下所示:
template<int val, typename... Params>
void doSomething(Params... args) {
doSomethingElse<val, Params...>(args...);
}
Run Code Online (Sandbox Code Playgroud)
我应该用它代替:
template<int val, typename... Params>
void doSomething(Params&&... args) {
doSomethingElse<val, Params...>(std::forward<Params>(args)...);
}
Run Code Online (Sandbox Code Playgroud)
另外,如果在函数中使用两次参数,即同时转发到两个函数,是否明智使用std::forward
?不会std::forward
将相同的东西转换为临时两次,移动内存并使其无效以供第二次使用?以下代码是否可以:
template<int val, typename... Params>
void doSomething(Params&&... args) {
doSomethingElse<val, Params...>(std::forward<Params>(args)...);
doSomethingWeird<val, Params...>(std::forward<Params>(args)...);
}
Run Code Online (Sandbox Code Playgroud)
我有点困惑std::forward
,我很乐意使用一些清理工作.
标准是否准确定义了对象移动后我可以对其做什么?我曾经认为你用移动物体做的所有事情都可以破坏它,但这还不够.
例如,采用swap
标准库中定义的函数模板:
template <typename T>
void swap(T& a, T& b)
{
T c = std::move(a); // line 1
a = std::move(b); // line 2: assignment to moved-from object!
b = std::move(c); // line 3: assignment to moved-from object!
}
Run Code Online (Sandbox Code Playgroud)
显然,必须可以分配给移动的对象,否则第2行和第3行将失败.那么移动对象我还能做些什么呢?我在哪里可以找到标准中的这些细节?
(顺便说一句,为什么它T c = std::move(a);
不是T c(std::move(a));
第1行呢?)
可能重复:
使用forward的优点
我知道它的作用以及何时使用它但我仍然无法理解其工作原理.请尽可能详细,并解释std::forward
如果允许使用模板参数推断,何时不正确.
我的一部分困惑是:"如果它有一个名字,它就是一个左值" - 如果是这样的话,为什么std::forward
当我通过thing&& x
vs 时表现不同thing& x
?
我一直认为std::forward
这只适用于模板参数.但是,我问自己为什么.请参阅以下示例:
void ImageView::setImage(const Image& image){
_image = image;
}
void ImageView::setImage(Image&& image){
_image = std::move(image);
}
Run Code Online (Sandbox Code Playgroud)
这两个功能基本上是一样的; 一个采用l值参考,另一个采用r值参考.现在,我认为,std::forward
如果参数是l值引用,则应返回l值引用,如果参数为1,则应返回r值引用,此代码可简化为如下所示:
void ImageView::setImage(Image&& image){
_image = std::forward(image);
}
Run Code Online (Sandbox Code Playgroud)
这类似于cplusplus.com提到的示例std::forward
(只是没有任何模板参数).我想知道,如果这是正确与否,如果不是为什么.
我也问自己究竟会有什么区别
void ImageView::setImage(Image& image){
_image = std::forward(image);
}
Run Code Online (Sandbox Code Playgroud) 当给出以下结构的代码时
template <typename... Args>
void foo(Args&&... args) { ... }
Run Code Online (Sandbox Code Playgroud)
我经常static_cast<Args&&>
在函数中看到库代码用于参数转发.通常,对此的理由是使用static_cast
避免不必要的模板实例化.
鉴于语言的参考折叠和模板扣除规则.我们得到了完美的转发,static_cast<Args&&>
这个声明的证据如下(在误差范围内,我希望答案会启发)
&& &&
- > &&
(1
上面的规则)& &&
- > &
(2
上面的规则)这基本上foo()
是bar()
在上面的例子中转发参数.这也是你在std::forward<Args>
这里使用时会得到的行为.
问题 -为什么要std::forward
在这些背景下使用?避免额外的实例化是否有理由违反惯例?
Howard Hinnant的论文n2951规定了6个约束,在这些约束条件下,任何实现都std::forward
应该"正确".这些曾经是
(1)和(2)证明与static_cast<Args&&>
上述方法一起正常工作.(3) - (6)这里不适用,因为在推导的上下文中调用函数时,这些都不会发生.
注意:我个人更喜欢使用std::forward
,但我的理由纯粹是我更喜欢坚持惯例.
我有一个基类,它基本上将一个类附加到任意窗口句柄(例如,HWND,HFONT),并使用策略类来附加/分离和销毁:
// class SmartHandle
template<typename THANDLE, class TWRAPPER, class TPOLICY>
class SmartHandle : boost::noncopyable
{
private:
TPOLICY* m_pPolicy; // Policy
bool m_bIsTemporary; // Is this a temporary window?
SmartHandle(); // no default ctor
SmartHandle(const SmartHandle<THANDLE, TWRAPPER, TPOLICY>&); // no cctor
protected:
THANDLE m_hHandle; // Handle to the underlying window
TPOLICY& policy() {return(*m_pPolicy);};
// ctor that attaches but is temporary
SmartHandle(const THANDLE& _handle, bool _temporary) : m_hHandle(_handle)
, m_bIsTemporary(_temporary)
{
m_pPolicy = new TPOLICY(reinterpret_cast<TWRAPPER&>(*this));
if(_handle)
m_pPolicy->attach(_handle);
}; // eo ctor
// …
Run Code Online (Sandbox Code Playgroud) 建议std::forward
通常仅限于完美转发函数模板参数的规范用例; 一些评论员甚至说这是唯一有效的用途std::forward
.但考虑这样的代码:
// 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_;
};
Run Code Online (Sandbox Code Playgroud)
在这种情况下,不会出现完美转发的问题:由于这是一个类模板而不是一个函数模板,客户端代码必须明确指定T
,并可以选择是否以及如何对其进行ref-qualify.出于同样的原因,论证std::forward
不是"普遍参考".
尽管如此,这std::forward
似乎是一个很好的选择:我们不能把它排除在外,因为当它T
是一个只移动类型时它不起作用,我们不能使用std::move
它,因为当它T
是一个左值引用类型时它不起作用.当然,我们可以部分专门ValueHolder
使用直接初始化引用和std::move
值,但这似乎std::forward
是工作时的过度复杂.对于以下含义,这似乎也是一个合理的概念匹配std::forward
:我们试图通常转发可能会或可能不会引用的内容,只有我们将它转发给函数的调用者,而不是我们调用的函数.我们自己.
这是一个合理的用途std::forward …
除非我错了,否则它们似乎都运行得很好 - 是否有一个最佳实践理由更喜欢一个而不是另一个?
例:
struct A
{
A(){}
A(const A&){ std::cout << "A(const A&)\n"; }
A(A&&){ std::cout << "A(A&&)\n"; }
};
struct B
{
B(){}
B(const B& right) : x(right.x){ std::cout << "B(const B&)\n"; }
B(B&& right) : x(std::forward<A>(right.x)){ std::cout << "B(B&&)\n"; }
A x;
};
struct C
{
C(){}
C(const C& right) : x(right.x){ std::cout << "C(const C&)\n"; }
C(C&& right) : x(std::move(right.x)){ std::cout << "C(C&&)\n"; }
A x;
};
struct D
{
D(){}
D(const D& right) : x(right.x){ …
Run Code Online (Sandbox Code Playgroud) 我注意到std::forward
在这方面没有用处:
void consumeObject(std::unique_ptr<Object>&& robj) {
myvector.emplace_back(std::forward<std::unique_ptr<Object>>(robj));
}
Run Code Online (Sandbox Code Playgroud)
这是为什么?我认为当rvalue引用绑定到一个函数参数时(即我可以通过名称引用它),它在该范围内变为左值,并且为了被传递,需要被转换为右值引用(如在完美转发中) ).
为什么它错了/没用?
我有一个名为Push
C++ 11中编写的方法的以下模板类(剥离以仅包含相关部分):
template<class T, int Capacity>
class CircularStack
{
private:
std::array<std::unique_ptr<T>, Capacity> _stack;
public:
void Push(std::unique_ptr<T>&& value)
{
//some code omitted that updates an _index member variable
_stack[_index] = std::move(value);
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:
我应该使用
std::move
还是std::forward
在内Push
?
我不确定是否std::unique_ptr<T>&&
有资格作为通用参考,因此应该使用forward
而不是move
.
我是C++的新手.