简体   繁体   English

为什么不总是使用std :: forward?

[英]Why not always use std::forward?

The distinction between std::move and std::forward is well known, we use the latter to preserve the value category of a forwarded object and the former to cast to rvalue reference in order to enable move semantics. std::movestd::forward之间的区别是众所周知的,我们使用后者保留转发对象的值类别,并使用前者转换为rvalue引用以启用移动语义。

In effective modern C++ , a guideline exists that states 有效的现代C ++中 ,存在一种指导原则

use std::move on rvalue references, std::forward on universal references. 在rvalue引用上使用std::move ,在通用引用上使用std::move std::forward

Yet in the following scenario ( and scenarios where we don't want to change value category ), 但在以下场景中( 以及我们不想更改值类别的场景 ),

template <class T>
void f(vector<T>&& a)
{
    some_func(std::move(a)); 
}

where a is not a forwarding reference but a simple rvalue reference, wouldn't it be exactly the same to do the following? 如果a不是转发引用而是简单的右值引用,那么执行以下操作是否完全相同?

template <class T>
void f(vector<T>&& a)
{
    some_func(std::forward<decltype(a)>(a)); 
}

Since this can be easily encapsulated in a macro like this, 因为这可以很容易地封装在像这样的宏中,

#define FWD(arg) std::forward<decltype(arg)>(arg)

isn't it convenient to always use this macro definition like so? 如此总是使用这个宏定义不方便吗?

void f(vector<T>&& a)
{
    some_func(FWD(a)); 
}

Aren't the two ways of writing this exactly equivalent? 写这两种方式不完全相同吗?

Eh. 呃。 Debatable. 值得商榷。 In your particular example it is equivalent. 在您的特定示例中,它是等效的。 But I wouldn't make it a habit. 但我不会养成习惯。 One reason is because you want a semantic distinction between forwarding and moving. 一个原因是因为您希望在转发和移动之间进行语义区分。 Another reason is because to have a consistent API you'd have to have MOV in addition to FWD , and that really looks bad and doesn't do anything. 另一个原因是因为要拥有一致的API,除了FWD之外你还必须拥有MOV ,这看起来很糟糕而且什么都不做。 More importantly, though, is that your code can fail unexpectedly. 但更重要的是,您的代码可能会意外失败。

Consider the following code: 请考虑以下代码:

#include <iostream>

using namespace std;

#define FWD(arg) std::forward<decltype(arg)>(arg)

struct S {
    S() { cout << "S()\n"; }
    S(const S&) { cout << "S(const S&)\n"; }
    S(S&&) { cout << "S(S&&)\n"; }
};

void some_func(S) {}

void f(S&& s)
{
    some_func(FWD(s)); 
}

int main()
{
    f(S{});
}

This prints out 打印出来

S() S()
S(S&&) 器S(s &&)

However, if I just change the FWD line to have another (seemingly optional) pair of parentheses, like this: 但是,如果我只是改变FWD线以获得另一对(看似可选的)括号,如下所示:

void f(S&& s)
{
    some_func(FWD((s))); 
}

Now we get 现在我们得到了

S() S()
S(const S&) S(const S&)

And this is because now we're using decltype on an expression, which evaluates to an lvalue reference. 这是因为现在我们在表达式上使用了decltype ,它计算为左值引用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM