简体   繁体   中英

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.

In effective modern C++ , a guideline exists that states

use std::move on rvalue references, std::forward on universal references.

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?

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. 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&&)

However, if I just change the FWD line to have another (seemingly optional) pair of parentheses, like this:

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

Now we get

S()
S(const S&)

And this is because now we're using decltype on an expression, which evaluates to an lvalue reference.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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