confused about std::forward

Hello everyone, I am learning about std::forward which is confusing.

The returned value type of std::forward keeps all the traits of its parameter.

If the real parameter is rvalue like 40 in the following code, after std::forward(40), the returned value type is rvalue reference, since it is anonymous, so it can be used as a rvalue (real parameter) passed to rvalue formal parameter v1 in f(int &&v1, int &v2). (Guess the logic up to now is correct)

While for a lvalue real parameter i, after std::forward, the returned type is lvalue reference. If use the logic in last paragraph, it is also an anonymous variable. Then it should also be regarded as a rvalue and should not be passed to lvalue reference v2 in f(int &&v1, int &v2). But it works.

What is wrong with the logic ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;

template <typename F, typename T1, typename T2>
void flip(F f, T1 &&t1, T2 &&t2)
{
    f(std::forward<T1>(t1), std::forward<T2>(t2));
}
void f(int &&v1, int &v2)
{
    cout << v1 << " " << ++v2 << endl;
    // other things...
}
int main()
{
    int i = 42;
    flip(f, 40, i);
    cout << "i = " << i << endl;
    return 0;
}
Last edited on
std::forward is simple in isolation -- it is equivalent to static_cast<T&&>(x) -- but the background information that's required is not.

since it is anonymous

Anonymity isn't the right criteria. Whether or not an expression e is an rvalue is better approximated by whether or not the expression &e compiles.

This is the best approximation I know of, and it isn't particularly good. To know for sure you'll need to become familiar with this reference page:
https://en.cppreference.com/w/cpp/language/value_category

Read this post as well:
https://www.cplusplus.com/forum/general/273175/#msg1178146

Last edited on
Oh, my god, I understand a little bit now.

the lvalue and rvalue are the traits of the expression. the value categories includes lvalue, rvalue(prvalue, and xvalue)...

For the std::forward<int>(40), (with a rvalue ref as returned type), it is a xvalue expression, which is still rvalue category instead of a lvaue, and so it can be passed to rvalue ref formal parameter.

While the std::forward<int>(i), (with a lvalue ref as the returned type), is lvalue expression, so it can be binded to lvalue ref.

Guess it is like this...
Guess it is like this...

Yes, you got it.
Topic archived. No new replies allowed.